-
-
Save mindplay-dk/3359812 to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* Benchmark: Reflection Performance | |
* | |
* Conclusion: there is no performance-gain from caching reflection-objects. | |
*/ | |
define('NUM_TESTS', 10); | |
header('Content-type: text/plain'); | |
$func = function($a, $b, $c) { | |
// ... | |
}; | |
class Foo | |
{ | |
public $a; | |
protected $b; | |
private $c; | |
public function foo($a,$b,$c) {} | |
protected function bar($a,$b,$c) {} | |
private function baz($a,$b,$c) {} | |
} | |
for ($i=0; $i<NUM_TESTS; $i++) { | |
$start = microtime(true); | |
$ref = new ReflectionClass($func); | |
$end = microtime(true); | |
echo "ReflectionClass # $i: " . number_format(1000000*($end-$start), 3) . " µsec\n"; | |
} | |
for ($i=0; $i<NUM_TESTS; $i++) { | |
$start = microtime(true); | |
$ref = new ReflectionFunction($func); | |
$end = microtime(true); | |
echo "ReflectionFunction # $i: " . number_format(1000000*($end-$start), 3) . " µsec\n"; | |
} | |
class Cache | |
{ | |
private $cache = array(); | |
public function getReflection($class) | |
{ | |
if (!isset($this->cache[$class])) { | |
$this->cache[$class] = new ReflectionClass($class); | |
} | |
return $this->cache[$class]; | |
} | |
} | |
$cache = new Cache; | |
for ($i=0; $i<NUM_TESTS; $i++) { | |
$start = microtime(true); | |
$ref = $cache->getReflection('Foo'); | |
$end = microtime(true); | |
echo "Cached ReflectionClass # $i: " . number_format(1000000*($end-$start), 3) . " µsec\n"; | |
} |
[matsu@teraren /tmp]% php reflection-bench.php
ReflectionClass # 0: 548.124 µsec
ReflectionClass # 1: 4.053 µsec
ReflectionClass # 2: 1.907 µsec
ReflectionClass # 3: 0.954 µsec
ReflectionClass # 4: 2.146 µsec
ReflectionClass # 5: 2.146 µsec
ReflectionClass # 6: 2.146 µsec
ReflectionClass # 7: 1.192 µsec
ReflectionClass # 8: 0.954 µsec
ReflectionClass # 9: 1.907 µsec
ReflectionFunction # 0: 15.974 µsec
ReflectionFunction # 1: 13.113 µsec
ReflectionFunction # 2: 1.907 µsec
ReflectionFunction # 3: 0.954 µsec
ReflectionFunction # 4: 0.954 µsec
ReflectionFunction # 5: 0.954 µsec
ReflectionFunction # 6: 0.954 µsec
ReflectionFunction # 7: 1.907 µsec
ReflectionFunction # 8: 1.907 µsec
ReflectionFunction # 9: 1.907 µsec
Cached ReflectionClass # 0: 556.946 µsec
Cached ReflectionClass # 1: 2.146 µsec
Cached ReflectionClass # 2: 2.146 µsec
Cached ReflectionClass # 3: 0.954 µsec
Cached ReflectionClass # 4: 0.954 µsec
Cached ReflectionClass # 5: 0.954 µsec
Cached ReflectionClass # 6: 0.954 µsec
Cached ReflectionClass # 7: 1.907 µsec
Cached ReflectionClass # 8: 0.954 µsec
Cached ReflectionClass # 9: 0.954 µsec
[matsu@teraren /tmp]% php -v
PHP 5.3.15 with Suhosin-Patch (cli) (built: Aug 28 2012 18:19:13)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
On L30, should be:
$ref = new ReflectionClass('Foo');
So that we can compare with the cached version on L61.
Thanks for the benchmark, by the way. I understand that there is no need to cache reflection objects.
PHP 7.2 Result for reference.
ReflectionClass # 0: 3.099 µsec
ReflectionClass # 1: 0.954 µsec
ReflectionClass # 2: 0.000 µsec
ReflectionClass # 3: 0.954 µsec
ReflectionClass # 4: 1.192 µsec
ReflectionClass # 5: 0.000 µsec
ReflectionClass # 6: 0.954 µsec
ReflectionClass # 7: 0.000 µsec
ReflectionClass # 8: 0.000 µsec
ReflectionClass # 9: 0.000 µsec
ReflectionFunction # 0: 0.954 µsec
ReflectionFunction # 1: 0.954 µsec
ReflectionFunction # 2: 0.000 µsec
ReflectionFunction # 3: 0.000 µsec
ReflectionFunction # 4: 0.000 µsec
ReflectionFunction # 5: 0.000 µsec
ReflectionFunction # 6: 0.954 µsec
ReflectionFunction # 7: 0.000 µsec
ReflectionFunction # 8: 0.000 µsec
ReflectionFunction # 9: 0.954 µsec
Cached ReflectionClass # 0: 3.815 µsec
Cached ReflectionClass # 1: 0.954 µsec
Cached ReflectionClass # 2: 0.000 µsec
Cached ReflectionClass # 3: 0.000 µsec
Cached ReflectionClass # 4: 0.000 µsec
Cached ReflectionClass # 5: 0.000 µsec
Cached ReflectionClass # 6: 0.000 µsec
Cached ReflectionClass # 7: 0.000 µsec
Cached ReflectionClass # 8: 0.000 µsec
Cached ReflectionClass # 9: 0.000 µsec
PHP 7.2.34 (cli) (built: Jan 1 2022 00:11:08) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
And here's PHP 8.1 result.
ReflectionClass # 0: 2.146 µsec
ReflectionClass # 1: 0.954 µsec
ReflectionClass # 2: 0.000 µsec
ReflectionClass # 3: 0.000 µsec
ReflectionClass # 4: 0.000 µsec
ReflectionClass # 5: 1.192 µsec
ReflectionClass # 6: 0.954 µsec
ReflectionClass # 7: 0.000 µsec
ReflectionClass # 8: 0.000 µsec
ReflectionClass # 9: 0.954 µsec
ReflectionFunction # 0: 0.954 µsec
ReflectionFunction # 1: 0.000 µsec
ReflectionFunction # 2: 0.000 µsec
ReflectionFunction # 3: 0.000 µsec
ReflectionFunction # 4: 0.000 µsec
ReflectionFunction # 5: 0.954 µsec
ReflectionFunction # 6: 0.000 µsec
ReflectionFunction # 7: 0.000 µsec
ReflectionFunction # 8: 0.000 µsec
ReflectionFunction # 9: 0.000 µsec
Cached ReflectionClass # 0: 2.861 µsec
Cached ReflectionClass # 1: 0.954 µsec
Cached ReflectionClass # 2: 0.954 µsec
Cached ReflectionClass # 3: 0.000 µsec
Cached ReflectionClass # 4: 0.000 µsec
Cached ReflectionClass # 5: 0.954 µsec
Cached ReflectionClass # 6: 0.000 µsec
Cached ReflectionClass # 7: 0.000 µsec
Cached ReflectionClass # 8: 0.954 µsec
Cached ReflectionClass # 9: 1.192 µsec
PHP 8.1.3 (cli) (built: Feb 21 2022 23:46:08) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.3, Copyright (c) Zend Technologies
Is that saying that Reflection almost does not affect the performance on PHP 8.1 and 7.2 ?
Is that saying that Reflection almost does not affect the performance on PHP 8.1 and 7.2 ?
I think it has a very minimal impact, so unless you're in a performance-critical scenario, I don't think you need to worry about reflections negatively affecting your application.
PHP 8.2.10:
ReflectionClass # 0: 1.907 µsec
ReflectionClass # 1: 0.954 µsec
ReflectionClass # 2: 0.000 µsec
ReflectionClass # 3: 0.000 µsec
ReflectionClass # 4: 0.000 µsec
ReflectionClass # 5: 0.000 µsec
ReflectionClass # 6: 0.000 µsec
ReflectionClass # 7: 0.000 µsec
ReflectionClass # 8: 0.000 µsec
ReflectionClass # 9: 0.000 µsec
ReflectionFunction # 0: 0.000 µsec
ReflectionFunction # 1: 0.000 µsec
ReflectionFunction # 2: 0.000 µsec
ReflectionFunction # 3: 0.000 µsec
ReflectionFunction # 4: 0.000 µsec
ReflectionFunction # 5: 0.000 µsec
ReflectionFunction # 6: 0.000 µsec
ReflectionFunction # 7: 0.000 µsec
ReflectionFunction # 8: 0.000 µsec
ReflectionFunction # 9: 0.000 µsec
Cached ReflectionClass # 0: 2.861 µsec
Cached ReflectionClass # 1: 0.000 µsec
Cached ReflectionClass # 2: 0.000 µsec
Cached ReflectionClass # 3: 0.000 µsec
Cached ReflectionClass # 4: 0.000 µsec
Cached ReflectionClass # 5: 0.000 µsec
Cached ReflectionClass # 6: 0.000 µsec
Cached ReflectionClass # 7: 0.000 µsec
Cached ReflectionClass # 8: 0.000 µsec
Cached ReflectionClass # 9: 0.000 µsec
PHP 8.2.10 (cli) (built: Sep 2 2023 06:59:22) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.10, Copyright (c) Zend Technologies
with Zend OPcache v8.2.10, Copyright (c), by Zend Technologies
PHP 8.3.10
ReflectionClass # 0: 5.007 µsec
ReflectionClass # 1: 2.861 µsec
ReflectionClass # 2: 0.954 µsec
ReflectionClass # 3: 0.000 µsec
ReflectionClass # 4: 0.954 µsec
ReflectionClass # 5: 0.954 µsec
ReflectionClass # 6: 0.000 µsec
ReflectionClass # 7: 0.000 µsec
ReflectionClass # 8: 0.954 µsec
ReflectionClass # 9: 0.954 µsec
ReflectionFunction # 0: 1.907 µsec
ReflectionFunction # 1: 1.907 µsec
ReflectionFunction # 2: 0.954 µsec
ReflectionFunction # 3: 0.000 µsec
ReflectionFunction # 4: 0.000 µsec
ReflectionFunction # 5: 0.954 µsec
ReflectionFunction # 6: 0.954 µsec
ReflectionFunction # 7: 0.000 µsec
ReflectionFunction # 8: 0.000 µsec
ReflectionFunction # 9: 0.000 µsec
Cached ReflectionClass # 0: 25.988 µsec
Cached ReflectionClass # 1: 0.954 µsec
Cached ReflectionClass # 2: 0.954 µsec
Cached ReflectionClass # 3: 0.954 µsec
Cached ReflectionClass # 4: 0.000 µsec
Cached ReflectionClass # 5: 0.000 µsec
Cached ReflectionClass # 6: 0.954 µsec
Cached ReflectionClass # 7: 0.954 µsec
Cached ReflectionClass # 8: 1.192 µsec
Cached ReflectionClass # 9: 0.000 µsec
php -v
PHP 8.3.10 (cli) (built: Jul 30 2024 13:44:37) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.10, Copyright (c) Zend Technologies
with Xdebug v3.3.2, Copyright (c) 2002-2024, by Derick Rethans
with Zend OPcache v8.3.10, Copyright (c), by Zend Technologies
It's obviously never zero - that's your computers being so fast now that microtime
doesn't have enough resolution to measure the actual time taken.
Here's a (Linux only) version of the script using hrtime
instead of microtime
:
<?php
/**
* Benchmark: Reflection Performance
*
* Conclusion: there is no performance-gain from caching reflection-objects.
*/
define('NUM_TESTS', 10);
header('Content-type: text/plain');
$func = function($a, $b, $c) {
// ...
};
class Foo
{
public $a;
protected $b;
private $c;
public function foo($a,$b,$c) {}
protected function bar($a,$b,$c) {}
private function baz($a,$b,$c) {}
}
for ($i=0; $i<NUM_TESTS; $i++) {
$start = hrtime(true);
$ref = new ReflectionClass($func);
$end = hrtime(true);
echo "ReflectionClass # $i: " . number_format($end-$start) . " µsec\n";
}
for ($i=0; $i<NUM_TESTS; $i++) {
$start = hrtime(true);
$ref = new ReflectionFunction($func);
$end = hrtime(true);
echo "ReflectionFunction # $i: " . number_format($end-$start) . " µsec\n";
}
class Cache
{
private $cache = array();
public function getReflection($class)
{
if (!isset($this->cache[$class])) {
$this->cache[$class] = new ReflectionClass($class);
}
return $this->cache[$class];
}
}
$cache = new Cache;
for ($i=0; $i<NUM_TESTS; $i++) {
$start = hrtime(true);
$ref = $cache->getReflection('Foo');
$end = hrtime(true);
echo "Cached ReflectionClass # $i: " . number_format($end-$start) . " µsec\n";
}
Current results on my system with PHP 8.2.19:
ReflectionClass # 0: 1,920 µsec
ReflectionClass # 1: 1,010 µsec
ReflectionClass # 2: 390 µsec
ReflectionClass # 3: 640 µsec
ReflectionClass # 4: 300 µsec
ReflectionClass # 5: 270 µsec
ReflectionClass # 6: 290 µsec
ReflectionClass # 7: 590 µsec
ReflectionClass # 8: 610 µsec
ReflectionClass # 9: 610 µsec
ReflectionFunction # 0: 1,130 µsec
ReflectionFunction # 1: 670 µsec
ReflectionFunction # 2: 300 µsec
ReflectionFunction # 3: 280 µsec
ReflectionFunction # 4: 610 µsec
ReflectionFunction # 5: 610 µsec
ReflectionFunction # 6: 600 µsec
ReflectionFunction # 7: 600 µsec
ReflectionFunction # 8: 600 µsec
ReflectionFunction # 9: 600 µsec
Cached ReflectionClass # 0: 5,130 µsec
Cached ReflectionClass # 1: 890 µsec
Cached ReflectionClass # 2: 370 µsec
Cached ReflectionClass # 3: 290 µsec
Cached ReflectionClass # 4: 630 µsec
Cached ReflectionClass # 5: 620 µsec
Cached ReflectionClass # 6: 630 µsec
Cached ReflectionClass # 7: 290 µsec
Cached ReflectionClass # 8: 630 µsec
Cached ReflectionClass # 9: 650 µsec
Note that the results vary a lot - this simple script is 10+ years old and not a good benchmark, but run it a few times and you'll still get the jist, that you should not be caching reflection classes. They are cached internally in PHP, better than anything you can do in userland. 🙂
I added this benchmark to the sandbox.
We can compare it on different versions of php.
the greater lesson here is "trust the language"
if you don't have a performance problem, don't optimize - especially not preemptively! there's a good chance the language will optimize later, and your "optimizations" become useless complexity, perhaps even slowing things down.
I've seen this happen with lots of things over the years - in different languages, in the browser, it's almost always safer and better in the long run to assume the language is good at what the language is supposed to do. 😄
do you mind posting the results of this test in the comments so we googlers can compare?