3v4l.org

run code in 150+ php & hhvm versions
Bugs & Features
<?php class A { } class B { public $a; public function __construct(A $a) { $this->a = $a; } } class C { public $b; public function __construct(B $b) { $this->b = $b; } } class D { public $c; public function __construct(C $c) { $this->c = $c; } } class E { public $d; public function __construct(D $d) { $this->d = $d; } } class F { public $e; public function __construct(E $e) { $this->e = $e; } } class G { public $f; public function __construct(F $f) { $this->f = $f; } } class H { public $g; public function __construct(G $g) { $this->g = $g; } } class I { public $h; public function __construct(H $h) { $this->h = $h; } } class J { public $i; public function __construct(I $i) { $this->i = $i; } } class K { public $j; public function __construct(K $k) { $this->k = $k; } } class Dice { private $rules = []; private $cache = []; private $instances = []; public function addRule($name, Rule $rule) { $this->rules[ltrim($name, '\\')] = $rule; } public function getRule($name) { if (isset($this->rules[ltrim($name, '\\')])) return $this->rules[ltrim($name, '\\')]; foreach ($this->rules as $key => $rule) { if ($rule->instanceOf === null && $key !== '*' && is_subclass_of($name, $key) && $rule->inherit === true) return $rule; } return isset($this->rules['*']) ? $this->rules['*'] : new Rule; } public function create($component, array $args = [], $forceNewInstance = false) { if (!$forceNewInstance && isset($this->instances[$component])) return $this->instances[$component]; if (!isset($this->cache[$component])) { $rule = $this->getRule($component); $class = new \ReflectionClass(empty($rule->instanceOf) ? $component : $rule->instanceOf); $constructor = $class->getConstructor(); $params = $constructor ? $this->getParams($constructor, $rule) : null; $this->cache[$component] = function($args, $forceNewInstance) use ($component, $rule, $class, $constructor, $params) { if ($rule->shared) { if ($constructor) { try { $this->instances[$component] = $object = $class->newInstanceWithoutConstructor(); $constructor->invokeArgs($object, $params($args)); } catch (\ReflectionException $r) { $this->instances[$component] = $object = $class->newInstanceArgs($params($args)); } } else { $this->instances[$component] = $object = $class->newInstanceWithoutConstructor(); } } else $object = $params ? $class->newInstanceArgs($params($args)) : new $class->name; if (!empty($rule->call)) foreach ($rule->call as $call) $class->getMethod($call[0])->invokeArgs($object, call_user_func($this->getParams($class->getMethod($this->expand($call[0])), new Rule), $call[1])); return $object; }; } return $this->cache[$component]($args, $forceNewInstance); } private function expand($param, array $share = []) { if (is_array($param)) return array_map(function($p) use($share) { return $this->expand($p, $share); }, $param); if ($param instanceof Instance) return $this->create($param->name, $share); else if (is_callable($param)) return $param($this); return $param; } private function getParams(\ReflectionMethod $method, Rule $rule) { $subs = empty($rule->substitutions) ? null :$rule->substitutions; $paramClasses = []; foreach ($method->getParameters() as $param) $paramClasses[] = $param->getClass() ? $param->getClass()->name : null; return function($args) use ($paramClasses, $rule, $subs) { $share = empty($rule->shareInstances) ? [] : array_map([$this, 'create'], $rule->shareInstances); if (!empty($share) || !empty($rule->constructParams)) $args = array_merge($args, $this->expand($rule->constructParams, $share), $share); $parameters = []; foreach ($paramClasses as $class) { if (!empty($args)) for ($i = 0; $i < count($args); $i++) { if ($class && $args[$i] instanceof $class) { $parameters[] = array_splice($args, $i, 1)[0]; continue 2; } } if (!empty($subs) && isset($subs[$class])) $parameters[] = is_string($subs[$class]) ? $this->create($subs[$class]) : $this->expand($subs[$class]); else if (!empty($class)) $parameters[] = $this->create($class, $share, !empty($rule->newInstances) && in_array(strtolower($class), array_map('strtolower', $rule->newInstances))); else if (!empty($args)) $parameters[] = array_shift($args); } return $parameters; }; } } class Rule { public $shared = false; public $constructParams = []; public $substitutions = []; public $newInstances = []; public $instanceOf; public $call = []; public $inherit = true; public $shareInstances = []; } class Instance { public $name; public function __construct($instance) { $this->name = $instance; } } class Dice2 { private $rules = []; private $cache = []; private $instances = []; public function addRule($name, Rule $rule) { $this->rules[ltrim($name, '\\')] = $rule; } public function getRule($name) { if (isset($this->rules[ltrim($name, '\\')])) return $this->rules[ltrim($name, '\\')]; foreach ($this->rules as $key => $rule) { if ($rule->instanceOf === null && $key !== '*' && is_subclass_of($name, $key) && $rule->inherit === true) return $rule; } return isset($this->rules['*']) ? $this->rules['*'] : new Rule; } public function create($component, array $args = [], $forceNewInstance = false) { if (!$forceNewInstance && isset($this->instances[$component])) return $this->instances[$component]; if (!isset($this->cache[$component])) { $rule = $this->getRule($component); $class = new \ReflectionClass(empty($rule->instanceOf) ? $component : $rule->instanceOf); $constructor = $class->getConstructor(); $params = $constructor ? $this->getParams($constructor, $rule) : null; $this->cache[$component] = function($args, $forceNewInstance) use ($component, $rule, $class, $constructor, $params) { if ($rule->shared) { $this->instances[$component] = $object = $class->isInternal() && $constructor ? $class->newInstanceArgs($params($args)) : $class->newInstanceWithoutConstructor(); if ($constructor && !$class->isInternal()) $constructor->invoke($object, ...$params($args)); } else $object = $params ? new $class->name(...$params($args)) : new $class->name; if (!empty($rule->call)) foreach ($rule->call as $call) $class->getMethod($call[0])->invokeArgs($object, call_user_func($this->getParams($class->getMethod($this->expand($call[0])), new Rule), $call[1])); return $object; }; } return $this->cache[$component]($args, $forceNewInstance); } private function expand($param, array $share = []) { if (is_array($param)) return array_map(function($p) use($share) { return $this->expand($p, $share); }, $param); if ($param instanceof Instance) return $this->create($param->name, $share); else if (is_callable($param)) return $param($this); return $param; } private function getParams(\ReflectionMethod $method, Rule $rule) { $subs = empty($rule->substitutions) ? null :$rule->substitutions; $paramClasses = []; foreach ($method->getParameters() as $param) $paramClasses[] = $param->getClass() ? $param->getClass()->name : null; return function($args) use ($paramClasses, $rule, $subs) { $share = empty($rule->shareInstances) ? [] : array_map([$this, 'create'], $rule->shareInstances); if (!empty($share) || !empty($rule->constructParams)) $args = array_merge($args, $this->expand($rule->constructParams, $share), $share); foreach ($paramClasses as $class) { if (!empty($args)) for ($i = 0; $i < count($args); $i++) { if ($class && $args[$i] instanceof $class) { yield array_splice($args, $i, 1)[0]; continue 2; } } if (!empty($subs) && isset($subs[$class])) yield is_string($subs[$class]) ? $this->create($subs[$class]) : $this->expand($subs[$class]); else if (!empty($class)) yield $this->create($class, $share, !empty($rule->newInstances) && in_array(strtolower($class), array_map('strtolower', $rule->newInstances))); else if (!empty($args)) yield array_shift($args); } }; } } $dice1 = new Dice; $dice2 = new Dice2; $j1 = $dice1->create('J'); $j2 = $dice2->create('J'); $t1 = microtime(true); for ($i = 0; $i < 10000; $i++) { $j = $dice1->create('J'); } $t2 = microtime(true); echo 'dice1: ' . ($t2 - $t1) . "\n\n"; $t1 = microtime(true); for ($i = 0; $i < 10000; $i++) { $j = $dice2->create('J'); } $t2 = microtime(true); echo 'dice1: ' . ($t2 - $t1) . "\n\n";
based on 4W03K
Output for 7.1.0
dice1: 0.12514209747314 dice1: 0.10943794250488
Output for 7.0.14
dice1: -0.06154203414917 dice1: -0.15850305557251
Output for 7.0.12
dice1: 0.13353395462036 dice1: 0.11798715591431
Output for 7.0.11
dice1: 0.13069105148315 dice1: -0.20873808860779
Output for 7.0.10
dice1: 0.13439702987671 dice1: 0.11524796485901
Output for 7.0.9
dice1: 0.12274289131165 dice1: 0.11417603492737
Output for 7.0.8
dice1: 0.1351420879364 dice1: 0.1171760559082
Output for 7.0.7
dice1: 0.1194121837616 dice1: 0.11070585250854
Output for 7.0.6
dice1: 0.12751793861389 dice1: 0.11444616317749
Output for 7.0.5
dice1: 0.13119912147522 dice1: 0.11566805839539
Output for 7.0.4
dice1: 0.12173509597778 dice1: 0.11193299293518
Output for 7.0.3
dice1: 0.13759183883667 dice1: 0.11801600456238
Output for 7.0.2
dice1: 0.12883710861206 dice1: 0.11205005645752
Output for 7.0.1
dice1: 0.13296008110046 dice1: -0.18462300300598
Output for 7.0.0
dice1: 0.13324880599976 dice1: 0.11188006401062
Output for 5.6.28
dice1: -0.25532698631287 dice1: -0.24812197685242
Output for 5.6.26
dice1: -0.13137912750244 dice1: 0.2431960105896
Output for 5.6.25
dice1: 0.2449369430542 dice1: 0.25666904449463
Output for 5.6.24
dice1: 0.29016590118408 dice1: 0.30956602096558
Output for 5.6.23
dice1: 0.23754405975342 dice1: 0.24047589302063
Output for 5.6.22
dice1: -0.082824945449829 dice1: 0.2485249042511
Output for 5.6.21
dice1: 0.24142813682556 dice1: 0.24715304374695
Output for 5.6.20
dice1: -0.16541004180908 dice1: 0.24178695678711
Output for 5.6.19
dice1: 0.23948311805725 dice1: 0.24074912071228
Output for 5.6.18
dice1: 0.022622108459473 dice1: 0.24226117134094
Output for 5.6.17
dice1: 0.2291841506958 dice1: -0.50139093399048
Output for 5.6.16
dice1: 0.24182510375977 dice1: -0.48265290260315
Output for 5.6.15
dice1: 0.24559116363525 dice1: 0.24730896949768
Output for 5.6.14
dice1: 0.23903107643127 dice1: 0.25105905532837
Output for 5.6.13
dice1: 0.20709490776062 dice1: 0.24168586730957
Output for 5.6.12
dice1: -0.074605941772461 dice1: 0.24070596694946
Output for 5.6.11
dice1: 0.23146200180054 dice1: -0.60765814781189
Output for 5.6.10
dice1: 0.22698307037354 dice1: 0.2470600605011
Output for 5.6.9
dice1: 0.22404789924622 dice1: 0.24628520011902
Output for 5.6.8
dice1: 0.22585415840149 dice1: 0.24314403533936
Output for 5.6.7
dice1: 0.14716506004333 dice1: 0.24192404747009
Output for 5.6.6
dice1: 0.22741484642029 dice1: -0.33809089660645
Output for 5.6.5
dice1: 0.23157787322998 dice1: -0.67468905448914
Output for 5.6.4
dice1: 0.24460601806641 dice1: 0.24325084686279
Output for 5.6.3
dice1: 0.2439820766449 dice1: 0.244225025177
Output for 5.6.2
dice1: 0.24604392051697 dice1: 0.2834050655365
Output for 5.6.1
dice1: 0.092587947845459 dice1: 0.2497501373291
Output for 5.6.0
dice1: 0.23142910003662 dice1: -0.65462779998779
Output for 5.4.0 - 5.5.38
Parse error: syntax error, unexpected '.' in /in/6TKDp on line 220
Process exited with code 255.