Benchmarking call_user_func

Posted: September 19th, 2008 | Author: | Filed under: PHP | Tags: | Comments Off on Benchmarking call_user_func

Calling object methods can be done in several ways:

  1. $oObject->method($param);
  2. $sMethod = 'method'; $oObject->{$sMethod}($param);
  3. call_user_func(array($oObject, 'method'), $param);

(call_user_method() function has been deprecated as of PHP 4.1.0, c.f. php.net.)

Intuitively the first type method calling is the preferred way to go both in terms of perfromance and readability. However, for the sake of generality (freedom, scripting or just exploiting the possibilities php provides), one of the latter two could be preferred. A quick performance comparisson may show which to use.

Code

The code used for testing is straight-forward: a single test class containing just methods performing a
php function, returning a value and one doing nothing. Each of these has a version that takes a parameter and one without.

class Test {
	public function methodPhpFuncParam($sTestString){
		strpos('something-something else', $sTestString);
	}
	public function methodPhpFuncNoParam(){
		strpos('something-something else', 'else');
	}

	public function methodReturnParam($sTestString){
		return strpos('something-something else', $sTestString);
	}
	public function methodReturnNoParam(){
		return strpos('something-something else', 'else');
	}
}

$oTest = new Test();
$sMethodPhpFuncParam = 'methodPhpFuncParam';
$sMethodPhpFuncNoParam = 'methodPhpFuncNoParam';
$sMethodReturnParam = 'methodReturnParam';
$sMethodReturnNoParam = 'methodReturnNoParam';

$sTestString = 'thing';
define('LARGE_NUMBER', 1e5);

and for each type of method call described above:

for ($i = 0; $i < LARGE_NUMBER; $i++){
	// specific call
}

So each type of call is done 100.000 times.

Test environment:
Intel(R) Celeron(R) M processor 1.30 GHz
2.0 GiB memory
php 5.2.4-2ubuntu5.3

Results

With parameter, returning Without parameter, returning With parameter, not returning Without parameter, not returning
$oObject->method($param); 2.12432 sec. 1.13043 sec. 1.10389 sec. 1.07097 sec.
$sMethod = 'method'; $oObject->;{$sMethod}($param); 1.16371 sec. 1.08813 sec. 1.10008 sec. 1.06675 sec.
call_user_func(array($oObject, 'method'), $param); 2.56013 sec. 2.41441 sec. 2.50614 sec. 2.66915 sec.

Conclusion

call_user_func is by far slowest of all method calls in all situations. But most interestingly, $oTest->{$sTestFunction}($sTestString); is faster than the default way of calling methods in all tests.

Just a hint: before using $oObject->{$sMethod}($param);, make sure it is callable. You can do so by checking

if (in_array($sMethod, get_class_methods($oObject)))

get_class_methods($oObject) returns an array containing public methods of $oObject, whereas is_callable and method_exists will also return private or protected methods.


Comments are closed.