Skip to content

Instantly share code, notes, and snippets.

@mindplay-dk
Created August 15, 2012 12:40
Show Gist options
  • Save mindplay-dk/3359812 to your computer and use it in GitHub Desktop.
Save mindplay-dk/3359812 to your computer and use it in GitHub Desktop.
A benchmark of reflection API performance in PHP
<?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";
}
@mindplay-dk
Copy link
Author

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. 🙂

@n-hor
Copy link

n-hor commented Nov 10, 2024

I added this benchmark to the sandbox.
We can compare it on different versions of php.

@mindplay-dk
Copy link
Author

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. 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment