3v4l.org

run code in 300+ PHP versions simultaneously
<?php // This is the class that we want to make lazy. // Note that this is an opaque class from the PoV of the proxy-generation logic: // its implementation details are unknown. class A { protected array $data = []; public function __construct() { $this->data = ['foo' => 123]; } public function __get($n) { return $this->data[$n] ?? null; } // line 15 public function __set($n, $v) { $this->data[$n] = $v; } public function __isset($n) { return isset($this->data[$n]); } public function __unset($n) { unset($this->data[$n]); } } // This is a simplified proxy class that would typically be generated automatically // from the signature of the proxied class. The way this works is by unsetting all // declared properties at instantiation time, then using the magic methods to lazily // initialize them on demand. This is a very simple implementation that does not handle // all edge cases, but it should be enough to illustrate the issue. The logic in each // magic method is very repetitive: we checks if we're trying to access the uninitialized // property. If yes, we initialize it, if not, we call the parent method. class LazyA extends A { private const STATUS_UNINITIALIZED = 0; private const STATUS_INITIALIZING = 1; private const STATUS_INITIALIZED = 2; private $lazyStatus = self::STATUS_UNINITIALIZED; public function __construct() { unset($this->data); } public function __get($n) { if (self::STATUS_INITIALIZED === $this->lazyStatus || 'data' !== $n) { if ('data' === $n && (new ReflectionProperty($this, 'data'))->isInitialized($this)) { return $this->data; } return parent::__get($n); } $this->initialize(); return $this->data; } public function __set($n, $v) { if (self::STATUS_INITIALIZED === $this->lazyStatus || 'data' !== $n) { parent::__set($n, $v); } $this->initialize(); $this->data = $v; } public function __isset($n) { if (self::STATUS_INITIALIZED === $this->lazyStatus || 'data' !== $n) { return parent::__isset($n); } $this->initialize(); return isset($this->data); } public function __unset($n) { if (self::STATUS_INITIALIZED === $this->lazyStatus || 'data' !== $n) { parent::__unset($n); } $this->initialize(); unset($this->data); } private function initialize() { if (self::STATUS_INITIALIZING === $this->lazyStatus) { return; } $this->lazyStatus = self::STATUS_INITIALIZING; parent::__construct(); $this->lazyStatus = self::STATUS_INITIALIZED; } } $a = new LazyA(); // Currently, this will trigger a TypeError: // Cannot assign null to property A::$data of type array on line 15 // With Ilija's patch, this will work as expected and will display int(123) var_dump($a->foo);

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.3.130.0080.00318.43
8.3.120.0000.00818.88
8.3.110.0000.00820.94
8.3.100.0000.00824.06
8.3.90.0040.01126.77
8.3.80.0090.00017.97
8.3.70.0160.00616.61
8.3.60.0130.00918.55
8.3.50.0120.00616.66
8.3.40.0070.00720.21
8.3.30.0130.00721.69
8.3.20.0040.00424.18
8.3.10.0080.00024.66
8.3.00.0060.00326.35
8.2.250.0120.00618.43
8.2.240.0030.00617.52
8.2.230.0040.00422.58
8.2.220.0050.00337.54
8.2.210.0070.00026.77
8.2.200.0030.00716.63
8.2.190.0060.00918.54
8.2.180.0120.00916.50
8.2.170.0090.00619.04
8.2.160.0100.00622.96
8.2.150.0080.00025.66
8.2.140.0160.00424.66
8.2.130.0030.00526.35
8.2.120.0050.00326.35
8.2.110.0030.00626.35
8.2.100.0040.00426.35
8.2.90.0060.00326.35
8.2.80.0030.00626.35
8.2.70.0060.00326.35
8.2.60.0040.00426.35
8.2.50.0040.00426.35
8.2.40.0040.00426.35
8.2.30.0090.00026.35
8.2.20.0000.00926.35
8.2.10.0030.00626.35
8.2.00.0040.00426.35
8.1.300.0110.00420.15
8.1.290.0100.00030.84
8.1.280.0070.01425.92
8.1.270.0000.00823.87
8.1.260.0040.00426.35
8.1.250.0040.00426.35
8.1.240.0000.00926.35
8.1.230.0030.00626.35
8.1.220.0060.00326.35
8.1.210.0060.00326.35
8.1.200.0090.00026.35
8.1.190.0000.00926.35
8.1.180.0090.00026.35
8.1.170.0060.00326.35
8.1.160.0030.00626.35
8.1.150.0060.00326.35
8.1.140.0060.00326.35
8.1.130.0030.00626.35
8.1.120.0040.00426.35
8.1.110.0040.00426.35
8.1.100.0040.00426.35
8.1.90.0030.00626.35
8.1.80.0080.00026.35
8.1.70.0040.00426.35
8.1.60.0050.00526.35
8.1.50.0090.00026.35
8.1.40.0060.00326.35
8.1.30.0060.00326.35
8.1.20.0060.00326.35
8.1.10.0030.00626.35
8.1.00.0040.00426.35

preferences:
24.91 ms | 403 KiB | 5 Q