PHP 5.6 introduced a cool feature called argument unpacking: the splat operator unpacks arrays or objects implementing Traversable interfaces into argument lists. Its most evident application is to call functions without having to resort to call_user_func_array().

For example, in pre-5.6 the only (sane) way was to use call_user_func_array() like this:

Since PHP 5.6 it is possible to do it this way:

New features are cool, and I wanted to benchmark it for a long time (how old is PHP 5.6?), but never had free time for that. Until today.

I was looking at Slim’s DeferredCallable::__invoke() implementation and wondered if it would benefit from a dynamic call:

So I decided to write a quick benchmark using PHPBench:

Benchmark parameters: 5 iterations, 1,000,000 revolutions, 2 warmup revolutions (please read the documentation for an explanation what this means).

I ran the benchmark against PHP 7.0, 7.1, and 7.2, both thread safe (ZTS) and non-thread safe (NTS) builds (what is this?).

These are the results of the benchmark (the table shows mode values).

Performance of call_user_func_array() vs dynamic call
call_user_func_array
Megaops/s
Dynamic Call
Megaops/s
PHP 7.0.30 NTS 10.66 11.34
PHP 7.0.30 ZTS 7.38 7.62
PHP 7.1.17 NTS 16.71 17.05
PHP 7.1.17 ZTS 11.42 11.62
PHP 7.2.5 NTS 17.23 21.46
PHP 7.2.5 ZTS 12.21 12.12

Conclusions:

  • for ZTS builds, performance of both methods is comparable;
  • for NTS builds, dynamic calls are faster than call_user_func_array();
  • NTS is faster than ZTS;
  • 7.2 is faster than 7.1, which is faster than 7.0 (at least in this particular case).
PHP: call_user_func_array vs Dynamic Call
Tagged on:     

Leave a Reply

Your email address will not be published. Required fields are marked *