well im learning to create a wordpress plugin
i downloaded one and read the codes, and i saw this
i assume 'foo' is the tag where it will add action to..
but what does the array() exactly do?
add_action('foo', array('foo1', 'foo2'));
i looked at http://codex.wordpress.org/Function_Reference/add_action
and there is no clear definition about it ..
Right, the first argument is the tag (to which you'll be adding the action), and the second argument specifies the function to call (i.e. your callback).
The second argument takes in a PHP callback, and as such, accepts a number of valid forms. Check this out for all of them :
PHP Callback Pseudo-Types
The type you've shown above is of type 2. The first element of the array specifies a class, and the second element specifies which function of the class you'd like to call.
So with the example you've given above, what that will do is that, whenever the foo() action is called, it will eventually call foo1->foo2() as well.
The second argument of the add_action function is the function to be called with the hook.
function hello_header() {
echo "I'm in the header!";
}
add_action('wp_head', 'hello_header');
The usage of an array as the second argument is to pass a objects method rather than just a regular function.
Have a read up on the how the call_user_func works. Should provide some more insight.
http://us2.php.net/manual/en/language.pseudo-types.php#language.types.callback(dead link)
Related
In this comment in the PHP manual, a user suggested a class which would implement an error handler capable to implement primitive type hinting for PHP.
I understand how that class operates, however, I would like to know if it is possible to bring it to another level: instead of only checking the argument value to see if it matches the "typehint", would it be possible to replace the value with another one if it does match, and how?
I was thinking about something along the line of:
if(gettype($funcValue) == $typeHint) {
// here replace $funcValue, for example $funcValue = new Example($funcValue);
}
and then have the function call proceed with the new value?
I have searched the manual but found nothing which could allow me to "hook" in the parameters' values, but it could be there and I simply didn't find it.
When reading YIi guide at this link: http://www.yiiframework.com/wiki/327/events-explained/, I have see this line:
...So earlier before raising the event we should have called, maybe inside the initialization method of the component, something like this:
$myComponent->onForestRan = array(new SomeOtherClass, 'eventHandler1');
I understand that this code will attach a handler to event, and the array on the left-hand side is a PHP callback function. However, what I really don't understand is its syntax, does it call a onforestRan() function (which is previously defined on $component--> see the Yii link above), if so it will not valid as it lack of $event argument. Or, if it is a callback, then I have never seen a way of using callback like this (if it is a callback where is call_user_func() or usort()..). Its syntax is really odd to me.
Could some one help me with this?
Thank so much!
It's not a callback perse, but you're telling Yii what action (i.e. what function) to perform on the event.
In the example given, when onForestRan happens, the eventHandler1 function from SomeOtherClass will be triggered.
When that page describes a callback, it's saying that whatever you assign to $myComponent->onForestRan needs to be a callback function. The callback isn't executed at that point, you're just letting Yii know which callback(s) to use when the event occurs.
More details:
onForestRan is a special property of $myComponent, as documented here. More details can be seen in CComponent. You can search the CComponent source for lines similar to line 113, where you can see the beginning of the logic for the special property. This is very similar to action* methods in the controller.
$CComponent->onWhatever is a special language construct in Yii. The "property" onWhatever is recognized in CComponent's magic __set-method and then handled as an event attachment.
Let me quote shamelessly from http://phpmaster.com/yii-under-the-hood-2/:
public function __set($name, $value){
if (strncasecmp($name, "on", 2) === 0 && method_exists($this, $name)) {
$name = strtolower($name);
if (!isset($this->_e[$name])) {
$this->_e[$name] = new CList();
}
return $this->_e[$name]->add($value);
}
}
The implementation first checks if the value of $name starts with the text “on” and that a method also exists with the same name as the value. If it does, Yii assumes $value is a representation of a callback which it needs to attach to the event defined by $name. Yii has a private member variable $_e which holds an array of callbacks keyed by event names, and it simply adds the callback to the list for the particular event key.
$_e => array(
'onUserRegistered' => array(
0 => array(object, 'sendMyEmail')
),
'onSomeOtherEvent'=>array(
0 => function(){}
1 => ...
)
)
I am writing a unit test for a method using PHPUnit. The method I am testing makes a call to the same method on the same object 3 times but with different sets of arguments. My question is similar to the questions asked here and here
The questions asked in the other posts have to do with mocking methods that only take one argument.
However, my method takes multiple arguments and I need something like this:
$mock->expects($this->exactly(3))
->method('MyMockedMethod')
->with(
$this->logicalOr(
$this->equalTo($arg1, $arg2, arg3....argNb),
$this->equalTo($arg1b, $arg2b, arg3b....argNb),
$this->equalTo($arg1c, $arg2c, arg3c....argNc)
)
);
This code doesn't work because equalTo() validates only one argument. Giving it more than one argument throws an exception:
Argument #2 of PHPUnit_Framework_Constraint_IsEqual::__construct() must be a numeric
Is there a way to do a logicalOr mocking for a method with more than one argument?
In my case the answer turned out to be quite simple:
$this->expects($this->at(0))
->method('write')
->with(/* first set of params */);
$this->expects($this->at(1))
->method('write')
->with(/* second set of params */);
The key is to use $this->at(n), with n being the Nth call of the method. I couldn't do anything with any of the logicalOr() variants I tried.
For others who are looking to both match input parameters and provide return values for multiple calls.. this works for me:
$mock->method('myMockedMethod')
->withConsecutive([$argA1, $argA2], [$argB1, $argB2], [$argC1, $argC2])
->willReturnOnConsecutiveCalls($retValue1, $retValue2, $retValue3);
Stubbing a method call to return the value from a map
$map = array(
array('arg1_1', 'arg2_1', 'arg3_1', 'return_1'),
array('arg1_2', 'arg2_2', 'arg3_2', 'return_2'),
array('arg1_3', 'arg2_3', 'arg3_3', 'return_3'),
);
$mock->expects($this->exactly(3))
->method('MyMockedMethod')
->will($this->returnValueMap($map));
Or you can use
$mock->expects($this->exactly(3))
->method('MyMockedMethod')
->will($this->onConsecutiveCalls('return_1', 'return_2', 'return_3'));
if you don't need to specify input arguments
In case someone finds this without looking at the correspondent section in the phpunit documentation, you can use the withConsecutive method
$mock->expects($this->exactly(3))
->method('MyMockedMethod')
->withConsecutive(
[$arg1, $arg2, $arg3....$argNb],
[arg1b, $arg2b, $arg3b....$argNb],
[$arg1c, $arg2c, $arg3c....$argNc]
...
);
The only downside of this being that the code MUST call the MyMockedMethod in the order of arguments supplied. I have not yet found a way around this.
I'm trying to create a hook in one Wordpress plugin that could be used by other plugins. First off, is this even possible? I'm also sending some additional args so this may be 2 questions in one since I've been having trouble finding definitive information on how to do this.
Here is what I've tried so far:
In the plugin that is creating the hook (call it Plugin 1) I added:
do_action('plugin1_hook', $customArg1, $customArg2, $customArg3);
at the point that I want the hook to fire. Then, in a different plugin (Plugin 2), I added:
add_action('plugin1_hook', 'my_function');
and
function my_function($customArg1, $customArg2, $customArg3) { //my code }
This does not seem to be firing the function, however.
My refence for this has been the Wordpress hook comment_post, which is defined by Wordpress as:
do_action('comment_post', $comment_ID, $commentdata['comment_approved']);
and I am using as:
add_action('comment_post', 'my_comment');
function my_comment($comment_id) { //my code }
The above snippet is functioning properly.
I thought I'd post this as an answer as it's a little clearer to explain :)
When you hook a function, but do not specify the number of arguments, WordPress will always pass back one argument.
You won't get errors for something like this;
function do_my_hook($arg1, $arg2 = '', $arg3 = '') {}
add_action('my_hook', 'do_my_hook');
But you will for something like this;
function do_my_hook($arg1, $arg2, $arg3) {}
add_action('my_hook', 'do_my_hook');
WordPress is trying to call do_my_hook(), but it's only passing back one argument. The first example uses PHP default function arguments, so that you can call a function without passing all available arguments, but without error.
The second example will trigger a 'missing argument(s)' PHP error, as all three arguments are required.
The fix?
add_action('my_hook', 'do_my_hook', 10, 3);
The idea behind defining how many arguments your function takes is to avoid errors like these (though technically they are as easily avoided using default arguments!).
My guess is the second plugin is loading after the first one, so the hook has already fired by the time you add an action to it. You might try this for the first plugin:
function my_custom_hook_insertion($arg1, $arg2, $arg3){
do_action('plugin1_hook', $arg1, $arg2, $arg3);
}
add_action('plugins_loaded', 'my_custom_hook_insertion');
That will wait until all plugins are loaded before firing the hook.
Changing my add_action to this fixed the problem:
add_action('plugin1_hook', 'my_function', 10, 3);
The 10 represents the priority, and the 3 represents the number of args that the function will take. I'm not exactly sure how the matching works, since the default is 1, and I use plenty of hooks without specifying 0 args and I've used hooks that pass more than 1 arg but only used 1 arg in my function signature. Source: WordPress Codex: Function Reference/add action
It is working though, so cross plugin hooks are possible.
I'm writing a construct in PHP where a parser determins which function to call dynamically, kind of like this:
// The definition of what to call
$function_call_spec = array( "prototype" => "myFunction",
"parameters" => array( "first_par" => "Hello",
"second_par" => "World"));
// Dispatch
$funcPrototype = $function_call_spec["prototype"];
$funcPrototype(); // Here we call function 'myFunction'.
This is all fine and dandy. But now comes the next step, passing the parameters, which I don't really know if it's possible the way I want to do it. It never stops amazing me however what script languages can do these days, so here goes:
One could pass the parameters to the function like this:
// Here we call function 'myFunction' with the array of parameters.
$funcPrototype( $function_call_spec["parameters"] );
However, I want to declare 'myFunction' properly with clear arguments etc:
function myFunction( $first_par, $second_par )
{
}
The question then follows - Is there any way to pass parameters to a function dynamically simply by looping through the parameter array?
To clarify, I don't want to do it like this:
$funcPrototype( $function_call_spec["parameters"]["first_par"],
$function_call_spec["parameters"]["second_par"] );
Because this requires my code to statically know details about myFunction, which goes against the whole idea.
Instead I would want to do it in some way like this maybe:
// Special magic PHP function which can be used for invoking functions dynamically
InvokeFunction( $funcPrototype, $function_call_spec["parameters"] );
Which then results in myFunction being called and all parameters in the array gets passed to each individual parameter variable in the prototype.
Any comments are welcome.
Regards.
/R
PS: None of the code in this post has been tested for typos etc.
You should use call_user_func_array which can call any function or method and takes parameteres from an array.
Alternatively you can use ReflectionFunction::invokeArgs, but there's no benefit over call_user_func_array unless you already use this class for someting else (like checking whether function you call accepts appropriate number and types of arguments).
call_user_func_array($funcPrototype, $function_call_spec["parameters"]);
You might want to create a wrapper that names the function to your preference, such as:
function InvokeFunction($function, $args = array()) {
return call_user_func_array($function, (array)$args);
}
With this function you can call it in 3 different ways:
$return = InvokeFunction('doStuff');
$return = InvokeFunction('doStuff', $single_arg);
$return = InvokeFunction('doStuff', $multiple_args);
call_user_func_array() is the best choice if you don't need to enforce the contract, otherwise use ReflectionFunction.
http://us2.php.net/create_function
When you use create_function(), your arguments are not evaluated until runtime. Pretty sweet.