|
Index: wp-includes/plugin.php |
|
=================================================================== |
|
--- wp-includes/plugin.php (revision 23307) |
|
+++ wp-includes/plugin.php (working copy) |
|
@@ -59,10 +59,10 @@ |
|
* @param string $tag The name of the filter to hook the $function_to_add to. |
|
* @param callback $function_to_add The name of the function to be called when the filter is applied. |
|
* @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. |
|
- * @param int $accepted_args optional. The number of arguments the function accept (default 1). |
|
+ * @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). |
|
* @return boolean true |
|
*/ |
|
-function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { |
|
+function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = null) { |
|
global $wp_filter, $merged_filters; |
|
|
|
$idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority); |
|
@@ -167,11 +167,13 @@ |
|
$args = func_get_args(); |
|
|
|
do { |
|
- foreach( (array) current($wp_filter[$tag]) as $the_ ) |
|
+ foreach( (array) current($wp_filter[$tag]) as $the_ ) { |
|
if ( !is_null($the_['function']) ){ |
|
+ $accepted_args = _wp_get_hook_handler_accepted_arg_count($the_['function'], $the_['accepted_args']); |
|
$args[1] = $value; |
|
- $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args'])); |
|
+ $value = call_user_func_array($the_['function'], array_slice($args, 1, $accepted_args)); |
|
} |
|
+ } |
|
|
|
} while ( next($wp_filter[$tag]) !== false ); |
|
|
|
@@ -226,8 +228,10 @@ |
|
|
|
do { |
|
foreach( (array) current($wp_filter[$tag]) as $the_ ) |
|
- if ( !is_null($the_['function']) ) |
|
- $args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); |
|
+ if ( !is_null($the_['function']) ) { |
|
+ $accepted_args = _wp_get_hook_handler_accepted_arg_count($the_['function'], $the_['accepted_args']); |
|
+ $args[0] = call_user_func_array($the_['function'], array_slice($args, 0, $accepted_args)); |
|
+ } |
|
|
|
} while ( next($wp_filter[$tag]) !== false ); |
|
|
|
@@ -254,7 +258,6 @@ |
|
* @param string $tag The filter hook to which the function to be removed is hooked. |
|
* @param callback $function_to_remove The name of the function which should be removed. |
|
* @param int $priority optional. The priority of the function (default: 10). |
|
- * @param int $accepted_args optional. The number of arguments the function accepts (default: 1). |
|
* @return boolean Whether the function existed before it was removed. |
|
*/ |
|
function remove_filter( $tag, $function_to_remove, $priority = 10 ) { |
|
@@ -328,9 +331,9 @@ |
|
* @param string $tag The name of the action to which the $function_to_add is hooked. |
|
* @param callback $function_to_add The name of the function you wish to be called. |
|
* @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. |
|
- * @param int $accepted_args optional. The number of arguments the function accept (default 1). |
|
+ * @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). |
|
*/ |
|
-function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) { |
|
+function add_action($tag, $function_to_add, $priority = 10, $accepted_args = null) { |
|
return add_filter($tag, $function_to_add, $priority, $accepted_args); |
|
} |
|
|
|
@@ -402,8 +405,10 @@ |
|
|
|
do { |
|
foreach ( (array) current($wp_filter[$tag]) as $the_ ) |
|
- if ( !is_null($the_['function']) ) |
|
- call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); |
|
+ if ( !is_null($the_['function']) ){ |
|
+ $accepted_args = _wp_get_hook_handler_accepted_arg_count($the_['function'], $the_['accepted_args']); |
|
+ call_user_func_array($the_['function'], array_slice($args, 0, $accepted_args)); |
|
+ } |
|
|
|
} while ( next($wp_filter[$tag]) !== false ); |
|
|
|
@@ -483,8 +488,10 @@ |
|
|
|
do { |
|
foreach( (array) current($wp_filter[$tag]) as $the_ ) |
|
- if ( !is_null($the_['function']) ) |
|
- call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); |
|
+ if ( !is_null($the_['function']) ) { |
|
+ $accepted_args = _wp_get_hook_handler_accepted_arg_count($the_['function'], $the_['accepted_args']); |
|
+ call_user_func_array($the_['function'], array_slice($args, 0, $accepted_args)); |
|
+ } |
|
|
|
} while ( next($wp_filter[$tag]) !== false ); |
|
|
|
@@ -787,3 +794,74 @@ |
|
return $function[0].$function[1]; |
|
} |
|
} |
|
+ |
|
+/** |
|
+ * Obtain the argument count for a hook callback (function/method/closure) via Reflection |
|
+ * |
|
+ * It used to be that if hook (filter/action) is called with more than one |
|
+ * argument, you would have to supply a 4th argument to |
|
+ * add_action()/add_filter() in order for those extra arguments to be passed |
|
+ * into the function. This is painful because it usually violates DRY |
|
+ * principles since the number of arguments that a function takes is already |
|
+ * defined when the function was defined and so it should already be known. It |
|
+ * is also painful to have to pass in the number of arguments because |
|
+ * add_action() and add_filter() take positional arguments and so you always |
|
+ * have to define the 3rd argument ($priority) in order to be able to specify |
|
+ * the 4th ($accepted_args). PHP now has an always-included Reflection |
|
+ * extension that allows it to introspect to programmatically determine the |
|
+ * number of arguments that a function or method takes. In older versions of |
|
+ * WordPress when support for PHP 4 was required, WordPress was not able to |
|
+ * take advantage of Reflection because it was first introduced in PHP 5. But |
|
+ * now that PHP 5.2 is required, we can take advantage of Reflection and |
|
+ * simplify the calls to add_action() and add_filter(). |
|
+ * |
|
+ * This function is a helper that is re-used in do_action(), apply_filters(), |
|
+ * and do_action_ref_array(). If the accepted_args has been supplied when |
|
+ * add_action()/add_filter() was called (and it is not the default of null) |
|
+ * then it will return that instead of trying to introspect for the number of |
|
+ * args. |
|
+ * |
|
+ * @package WordPress |
|
+ * @subpackage Plugin |
|
+ * @access private |
|
+ * @since 3.6 |
|
+ * @link http://core.trac.wordpress.org/ticket/14671 |
|
+ * @link http://php.net/manual/en/book.reflection.php |
|
+ * |
|
+ * @param callable $function The filter/action handler supplied when calling add_action()/add_filter() |
|
+ * @param int $accepted_args The 4th argument passed into add_action()/add_filter() |
|
+ * @return int The number of arguments to pass into hook handler |
|
+ */ |
|
+function _wp_get_hook_handler_accepted_arg_count($function, $accepted_args) { |
|
+ static $callable_arg_count_cache = array(); |
|
+ |
|
+ // Note is_callable() is better for methods than method_exists() because it will work with __call magic methods |
|
+ if ( is_null($accepted_args) && is_callable($function) ) { |
|
+ $arg_count_cache_key = null; |
|
+ if (is_object($function) && ($function instanceof Closure)) { |
|
+ $arg_count_cache_key = spl_object_hash($function); |
|
+ } |
|
+ else if (is_array($function)) { |
|
+ $arg_count_cache_key = (is_object($function[0]) ? spl_object_hash($function[0]) : $function[0]); |
|
+ $arg_count_cache_key .= '::' . $function[1]; |
|
+ } |
|
+ else { |
|
+ assert(is_string($function)); |
|
+ $arg_count_cache_key = $function; |
|
+ } |
|
+ |
|
+ if (isset($callable_arg_count_cache[$arg_count_cache_key])) { |
|
+ $accepted_args = $callable_arg_count_cache[$arg_count_cache_key]; |
|
+ } else { |
|
+ if ( is_array($function) ) { |
|
+ list( $object, $method ) = $function; |
|
+ $reflection = new ReflectionMethod( $object, $method ); |
|
+ } else { |
|
+ $reflection = new ReflectionFunction( $function ); |
|
+ } |
|
+ $accepted_args = $reflection->getNumberOfParameters(); |
|
+ $callable_arg_count_cache[$arg_count_cache_key] = $accepted_args; |
|
+ } |
|
+ } |
|
+ return (int) $accepted_args; |
|
+} |