Make WordPress Core

Ticket #14671: 14671.4.diff

File 14671.4.diff, 7.5 KB (added by westonruter, 12 years ago)

Patch which allows omission 4th argument by using PHP Reflection to look up the number of accepted parameters from the supplied function

  • wp-includes/plugin.php

     
    5959 * @param string $tag The name of the filter to hook the $function_to_add to.
    6060 * @param callback $function_to_add The name of the function to be called when the filter is applied.
    6161 * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
    62  * @param int $accepted_args optional. The number of arguments the function accept (default 1).
     62 * @param int $accepted_args optional. The number of arguments the function accept (default: number of required arguments introspected from $function_to_add via the PHP Reflection API).
    6363 * @return boolean true
    6464 */
    65 function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
     65function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = null) {
    6666        global $wp_filter, $merged_filters;
    6767
    6868        $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
     
    167167                $args = func_get_args();
    168168
    169169        do {
    170                 foreach( (array) current($wp_filter[$tag]) as $the_ )
     170                foreach( (array) current($wp_filter[$tag]) as $the_ ) {
    171171                        if ( !is_null($the_['function']) ){
     172                                $accepted_args = _wp_get_hook_handler_accepted_arg_count($the_['function'], $the_['accepted_args']);
    172173                                $args[1] = $value;
    173                                 $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
     174                                $value = call_user_func_array($the_['function'], array_slice($args, 1, $accepted_args));
    174175                        }
     176                }
    175177
    176178        } while ( next($wp_filter[$tag]) !== false );
    177179
     
    226228
    227229        do {
    228230                foreach( (array) current($wp_filter[$tag]) as $the_ )
    229                         if ( !is_null($the_['function']) )
    230                                 $args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
     231                        if ( !is_null($the_['function']) ) {
     232                                $accepted_args = _wp_get_hook_handler_accepted_arg_count($the_['function'], $the_['accepted_args']);
     233                                $args[0] = call_user_func_array($the_['function'], array_slice($args, 0, $accepted_args));
     234                        }
    231235
    232236        } while ( next($wp_filter[$tag]) !== false );
    233237
     
    254258 * @param string $tag The filter hook to which the function to be removed is hooked.
    255259 * @param callback $function_to_remove The name of the function which should be removed.
    256260 * @param int $priority optional. The priority of the function (default: 10).
    257  * @param int $accepted_args optional. The number of arguments the function accepts (default: 1).
    258261 * @return boolean Whether the function existed before it was removed.
    259262 */
    260263function remove_filter( $tag, $function_to_remove, $priority = 10 ) {
     
    328331 * @param string $tag The name of the action to which the $function_to_add is hooked.
    329332 * @param callback $function_to_add The name of the function you wish to be called.
    330333 * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
    331  * @param int $accepted_args optional. The number of arguments the function accept (default 1).
     334 * @param int $accepted_args Optional. The number of arguments the function accept (default: number of required arguments introspected from $function_to_add via the PHP Reflection API).
    332335 */
    333 function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
     336function add_action($tag, $function_to_add, $priority = 10, $accepted_args = null) {
    334337        return add_filter($tag, $function_to_add, $priority, $accepted_args);
    335338}
    336339
     
    402405
    403406        do {
    404407                foreach ( (array) current($wp_filter[$tag]) as $the_ )
    405                         if ( !is_null($the_['function']) )
    406                                 call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
     408                        if ( !is_null($the_['function']) ){
     409                                $accepted_args = _wp_get_hook_handler_accepted_arg_count($the_['function'], $the_['accepted_args']);
     410                                call_user_func_array($the_['function'], array_slice($args, 0, $accepted_args));
     411                        }
    407412
    408413        } while ( next($wp_filter[$tag]) !== false );
    409414
     
    483488
    484489        do {
    485490                foreach( (array) current($wp_filter[$tag]) as $the_ )
    486                         if ( !is_null($the_['function']) )
    487                                 call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
     491                        if ( !is_null($the_['function']) ) {
     492                                $accepted_args = _wp_get_hook_handler_accepted_arg_count($the_['function'], $the_['accepted_args']);
     493                                call_user_func_array($the_['function'], array_slice($args, 0, $accepted_args));
     494                        }
    488495
    489496        } while ( next($wp_filter[$tag]) !== false );
    490497
     
    787794                return $function[0].$function[1];
    788795        }
    789796}
     797
     798/**
     799 * Obtain the argument count for a hook callback (function/method/closure) via Reflection
     800 *
     801 * It used to be that if hook (filter/action) is called with more than one
     802 * argument, you would have to supply a 4th argument to
     803 * add_action()/add_filter() in order for those extra arguments to be passed
     804 * into the function. This is painful because it usually violates DRY
     805 * principles since the number of arguments that a function takes is already
     806 * defined when the function was defined and so it should already be known. It
     807 * is also painful to have to pass in the number of arguments because
     808 * add_action() and add_filter() take positional arguments and so you always
     809 * have to define the 3rd argument ($priority) in order to be able to specify
     810 * the 4th ($accepted_args). PHP now has an always-included Reflection
     811 * extension that allows it to introspect to programmatically determine the
     812 * number of arguments that a function or method takes. In older versions of
     813 * WordPress when support for PHP 4 was required, WordPress was not able to
     814 * take advantage of Reflection because it was first introduced in PHP 5. But
     815 * now that PHP 5.2 is required, we can take advantage of Reflection and
     816 * simplify the calls to add_action() and add_filter().
     817 *
     818 * This function is a helper that is re-used in do_action(), apply_filters(),
     819 * and do_action_ref_array(). If the accepted_args has been supplied when
     820 * add_action()/add_filter() was called (and it is not the default of null)
     821 * then it will return that instead of trying to introspect for the number of
     822 * args.
     823 *
     824 * @package WordPress
     825 * @subpackage Plugin
     826 * @access private
     827 * @since 3.6
     828 * @link http://core.trac.wordpress.org/ticket/14671
     829 * @link http://php.net/manual/en/book.reflection.php
     830 *
     831 * @param callable $function The filter/action handler supplied when calling add_action()/add_filter()
     832 * @param int $accepted_args The 4th argument passed into add_action()/add_filter()
     833 * @return int The number of arguments to pass into hook handler
     834 */
     835function _wp_get_hook_handler_accepted_arg_count($function, $accepted_args) {
     836        // Note is_callable() is better for methods than method_exists() because it will work with __call magic methods
     837        if ( is_null($accepted_args) && is_callable($function) ) {
     838                if ( is_array($function) ) {
     839                        list( $object, $method ) = $function;
     840                        $reflection = new ReflectionMethod( $object, $method );
     841                } else {
     842                        $reflection = new ReflectionFunction( $function );
     843                }
     844                $accepted_args = $reflection->getNumberOfParameters();
     845        }
     846        return (int) $accepted_args;
     847}