3v4l.org

run code in 500+ PHP versions simultaneously
<?php declare(strict_types=1); /* |-------------------------------------------------------------------------- | Benchmark: | | 1. Dynamic call: | $instance->$method(...$args) | | 2. Reflection: | ReflectionMethod::invoke() | | 3. Cached first-class callable: | self::method(...) | | 4. Cached closure + Closure::call() | | This benchmark is specifically useful for: | - AOP | - proxy dispatch | - interceptor systems | - generated wrappers | |-------------------------------------------------------------------------- */ final class Bench { private int $value = 42; public function targetMethod(int $a, int $b): int { return $this->value + $a + $b; } public function run(int $iterations = 5_000_000): void { $method = 'targetMethod'; $args = [10, 20]; echo "Iterations: {$iterations}\n"; echo "Object ID : " . spl_object_id($this) . "\n"; echo str_repeat('-', 70) . "\n"; /* * Warmup (important for fair benchmark) */ for ($i = 0; $i < 10000; $i++) { $this->targetMethod(1, 2); } /* * Reflection prepared once */ $reflection = new ReflectionMethod(self::class, 'targetMethod'); /* * First-class callable prepared once * * You can test BOTH variants: * * Variant A: * $cachedClosure = $this->targetMethod(...); * * Variant B: * $cachedClosure = self::targetMethod(...); * * (both valid inside object context) */ $cachedClosure = self::targetMethod(...); /* * Another object for Closure::call() */ $another = new self(); /* * Prevent optimizer from eliminating calls */ $checksum = 0; /* |-------------------------------------------------------------------------- | 1. Dynamic method call |-------------------------------------------------------------------------- */ $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $checksum += $this->$method(...$args); } $dynamicTime = hrtime(true) - $start; /* |-------------------------------------------------------------------------- | 2. ReflectionMethod::invoke() |-------------------------------------------------------------------------- */ $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $checksum += $reflection->invoke($this, ...$args); } $reflectionTime = hrtime(true) - $start; /* |-------------------------------------------------------------------------- | 3. Cached closure direct call |-------------------------------------------------------------------------- */ $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $checksum += $cachedClosure(...$args); } $closureTime = hrtime(true) - $start; /* |-------------------------------------------------------------------------- | 4. Cached closure + Closure::call() |-------------------------------------------------------------------------- */ $start = hrtime(true); for ($i = 0; $i < $iterations; $i++) { $checksum += $cachedClosure->call($another, ...$args); } $callTime = hrtime(true) - $start; echo "Checksum (ignore): {$checksum}\n"; echo str_repeat('-', 70) . "\n"; $this->printResult('1. Dynamic $obj->$method()', $dynamicTime, $iterations); $this->printResult('2. ReflectionMethod::invoke()', $reflectionTime, $iterations); $this->printResult('3. Cached closure direct', $closureTime, $iterations); $this->printResult('4. Closure->call()', $callTime, $iterations); echo str_repeat('-', 70) . "\n"; echo "Lower is better\n"; } private function printResult( string $label, int $nanoseconds, int $iterations ): void { $ms = $nanoseconds / 1_000_000; $nsPerOp = $nanoseconds / $iterations; printf( "%-35s %12.3f ms (%8.2f ns/op)\n", $label, $ms, $nsPerOp ); } } (new Bench())->run();
Output for git.master_jit
Iterations: 5000000 Object ID : 1 ---------------------------------------------------------------------- Checksum (ignore): 1440000000 ---------------------------------------------------------------------- 1. Dynamic $obj->$method() 344.754 ms ( 68.95 ns/op) 2. ReflectionMethod::invoke() 276.221 ms ( 55.24 ns/op) 3. Cached closure direct 179.867 ms ( 35.97 ns/op) 4. Closure->call() 312.201 ms ( 62.44 ns/op) ---------------------------------------------------------------------- Lower is better
Output for git.master
Iterations: 5000000 Object ID : 1 ---------------------------------------------------------------------- Checksum (ignore): 1440000000 ---------------------------------------------------------------------- 1. Dynamic $obj->$method() 302.357 ms ( 60.47 ns/op) 2. ReflectionMethod::invoke() 281.447 ms ( 56.29 ns/op) 3. Cached closure direct 181.577 ms ( 36.32 ns/op) 4. Closure->call() 356.646 ms ( 71.33 ns/op) ---------------------------------------------------------------------- Lower is better

This tab shows result from various feature-branches currently under review by the php developers. Contact me to have additional branches featured.

Active branches

Archived branches

Once feature-branches are merged or declined, they are no longer available. Their functionality (when merged) can be viewed from the main output page


preferences:
40.07 ms | 735 KiB | 4 Q