3v4l.org

run code in 300+ PHP versions simultaneously
<?php class InstantiationCounter { public static $counts = []; public static function reset() { self::$counts = [ 'Database' => 0, 'Logger' => 0, 'A' => 0, 'B' => 0, 'C' => 0, 'D' => 0, ]; } } class Database { public function __construct() { InstantiationCounter::$counts['Database']++; } } class Logger { public function __construct() { InstantiationCounter::$counts['Logger']++; } } class A { public $database; public function __construct(Database $database) { InstantiationCounter::$counts['A']++; $this->database = $database; } } class B { public $database; public $logger; public function __construct(Database $database, Logger $logger) { InstantiationCounter::$counts['B']++; $this->database = $database; $this->logger = $logger; } } class C { public $a; public $b; public function __construct(A $a, B $b) { InstantiationCounter::$counts['C']++; $this->a = $a; $this->b = $b; } } class D { public $a; public $b; public $c; public function __construct(A $a, B $b, C $c) { InstantiationCounter::$counts['D']++; $this->a = $a; $this->b = $b; $this->c = $c; } } class Container { protected $classIsInstantiatableCache = []; protected $isStaticMethodCache = []; protected $definitions = []; public function get($className) { // If there is a manually defined dependency, use it if (isset($this->definitions[$className])) { return $this->definitions[$className](); } if (!isset($this->classIsInstantiatableCache[$className])) { $reflector = new ReflectionClass($className); $this->classIsInstantiatableCache[$className] = $reflector->isInstantiable(); } if (!$this->classIsInstantiatableCache[$className]) { throw new Exception("[$className] is not instantiable"); } $constructor = (new ReflectionClass($className))->getConstructor(); if (is_null($constructor)) { return new $className; } $parameters = $constructor->getParameters(); $dependencies = []; foreach($parameters as $parameter) { $type = $parameter->getType(); if (is_null($type) || $type->isBuiltin()) { throw new Exception("Can't resolve class dependency [$parameter]"); } $dependency = $type instanceof ReflectionNamedType ? $type->getName() : null; if (is_null($dependency)) { throw new Exception("Can't resolve class dependency [$parameter]"); } if (!isset($this->isStaticMethodCache[$dependency])) { $this->isStaticMethodCache[$dependency] = (new ReflectionClass($dependency))->getMethod('__construct')->isStatic(); } if ($this->isStaticMethodCache[$dependency]) { $dependencies[] = $dependency::getInstance(); } else { $dependencies[] = $this->get($dependency); } } return (new ReflectionClass($className))->newInstanceArgs($dependencies); } public function set($className, callable $factory) { $this->definitions[$className] = $factory; } } // Benchmark $iterations = 100000; $start = $end = null; InstantiationCounter::reset(); $container = new Container; // Benchmark: Instantiate $iterations of class D with autowiring $start = microtime(true); for ($i = 0; $i < $iterations; $i++) { $instance = $container->get('D'); } $end = microtime(true); echo "Time to instantiate $iterations of class D with autowiring: " . ($end - $start) . " seconds\n"; var_export( InstantiationCounter::$counts ); InstantiationCounter::reset(); $container = new Container(); $container->set('Database', function () { return new Database(); }); $container->set('Logger', function () { return new Logger(); }); $container->set('A', function () use ($container) { return new A($container->get('Database')); }); $container->set('B', function () use ($container) { return new B($container->get('Database'), $container->get('Logger')); }); $container->set('C', function () use ($container) { return new C($container->get('A'), $container->get('B')); }); $container->set('D', function () use ($container) { return new D($container->get('A'), $container->get('B'), $container->get('C')); }); // Benchmark: Instantiate $iterations of class D without autowiring $start = microtime(true); for ($i = 0; $i < $iterations; $i++) { $instance = $container->get('D'); #$instance = new D(new A(new Database()), new B(new Database(), new Logger()), new C(new A(new Database()), new B(new Database(), new Logger()))); } $end = microtime(true); echo "\nTime to instantiate $iterations of class D without autowiring: " . ($end - $start) . " seconds\n"; var_export( InstantiationCounter::$counts ); ?>
Output for 8.2.6
Time to instantiate 100000 of class D with autowiring: 1.2306959629059 seconds array ( 'Database' => 400000, 'Logger' => 200000, 'A' => 200000, 'B' => 200000, 'C' => 100000, 'D' => 100000, ) Time to instantiate 100000 of class D without autowiring: 0.21059584617615 seconds array ( 'Database' => 400000, 'Logger' => 200000, 'A' => 200000, 'B' => 200000, 'C' => 100000, 'D' => 100000, )

preferences:
52.97 ms | 401 KiB | 6 Q