New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
call $callback via call_user_func #62
Conversation
this will allow the use of static methods also wrote a test case for this scenario
I'm not keen on merging this. From my experience FYI, as a workaround you can make a string callable using the following pattern <?php
function make_callable($function) {
return function () use ($function) {
return call_user_func_array($function, func_get_args());
};
} Here's an example <?php
$phpinfo = make_callable('phpinfo');
$phpinfo(); |
I'll create some benchmarks. The passing by reference is needed when the callback is defined as a function that takes references. Otherwise call_user_func will fail since the function does not match the args given to call_user_func. Your example is pretty much what i changed in the code, except it adds even more overhead to calling a static method. Alternatively, you could send it through call_user_func only when it is actually needed. function make_callable($callback) {
if(is_array($callback) || (is_string($callback) && strpos($callback, '::') !== false) ) {
return function () use ($callback) {
return call_user_func_array($callback, func_get_args());
};
}
else {
return $callback;
}
} But then again, if performance is an issue, that extra function call is a killer compared to what we are trying to avoid. I made a bench of the above function vs. calling Results:
(code https://gist.github.com/4326951 ) Obviously, sending it all trough a make_callable is a bad idea. We knew that. Now, when looking at the middle result section, we see that using call_user_func with a plain function name, compared to calling it just by name has a diff time of 0.34600496292 seconds. devide that with the number of iterations and we get ~350 nanoseconds in average extra call time. Let us assume that in any given app, a maximum number of 100 routes pr. request is called. That will add 35ms extra time to the request. Compared to any regex routing and whatever business logic might be in these fictive 100 routes, the 350 nanoseconds extra is nothing. |
(also notice that just calling it through |
Thanks for the analysis. Not sure what you mean by "passing by reference is needed when the callback is defined as a function that takes references" - call-time pass by reference was deprecated in 5.3 and removed in 5.4. |
This is only an issue with $a = $b = $c = 10;
function f1($i, $j, $k) {
return $i+$j+$k;
}
function f2(&$i, &$j, &$k) {
return $i+$j+$k;
}
print call_user_func('f1', $a, $b, $c)."\n"; //ok
print call_user_func('f2', &$a, &$b, &$c)."\n"; //ok
print call_user_func('f2', $a, $b, $c)."\n"; //wont work will output
php version is 5.3.15 EDIT: Also, it is not needed if everyone just defines route callbacks as seen in |
Interesting. I can't see why anyone would define a route handler like |
I'm so lost at this point what this is even helping. See |
i suspect this to be a feature of php5.4 Class C {
static function f() {
return "hello word";
}
}
$f = 'C::f';
$f(); will output
If you want to do this you would have to devide the class name and method name like so: $c = 'C';
$f = 'f';
print $c::$f(); An alternate option for klein is to check for the '::' substring, or if callback is an array, and call in an alternate way if that is the case. I will do a bench again to see if it is faster. |
Is it faster to just pass the string to call_user_func and let that handle it, or to check for :: and call it like
Obviously, using call_user_func is faster. ( test code for good measure: https://gist.github.com/4335592 , and once again, php version 5.3.15 ) |
there we go. References removed. |
call $callback via call_user_func
Thanks |
I needed the ability to route to HTTPResource::GET, HTTPResource::PUT etc.
so i changed the way klein calls the route handlers.
By using call_user_func, any callable will be accepted as valid.
Should be fully backwards compatible.
Also added a test to ensure it actually works.