3v4l.org

run code in 300+ PHP versions simultaneously
<?php /** * TODO: Fix shitty doc. * * Provides type assertions for public object properties. All public properties are affected by this library. The * following assertions are provided: * * - Read-only property: the property can be accessed by everything, but only the object itself can modify it. This is * the default behavior af all public properties, unless configured otherwise. * - Guarded property: the property can be set by everything, but the value must pass a custom check for type/format, * provided by the object. * * In both cases the checks only apply for external callers (outside the object). Public properties can't be unset * (they can still be set to null, however). The trait also protects against dynamic properties being set on the object. */ trait PropAssert { // TODO: Move out all method bodies to another class, so code is loaded only if uses (i.e. with assertions enabled)? protected $__propAssert = []; /** * Initializes PropAssert. This method should be called once for each object, preferably at construction time. * * @return bool Always returns true, so it can be comfortably invoked in an assert statement. */ protected function initPropAssert(): bool { $refl = new \ReflectionClass(get_class($this)); $propList = $refl->getProperties(\ReflectionProperty::IS_PUBLIC); foreach ($propList as $prop) { $name = $prop->name; $this->__propAssert[$name] = [ 'guard' => null, 'value' => $this->{$name}, ]; unset($this->{$name}); } return true; } /** * Configured how a given public property is handled. By default, public properties are read-only. With this * method, * they can be set as writable, with a "guard" function, that checks the type and format of the value being set. * * @param string $name A public property name (the property should already be declared as public). * @param \Closure|null $guard A closure that guards the property while being set, or null to make the property * read-only (all public properties are read-only by default). If provided, the closure * should be in format ($value) => bool|string. The guard accepts a value about to be * set for the given property, and returns true if the value is valid, and false or a * string error message (for ex. "a string of length 6-32 chars"), if the value is * invalid. * @return bool Always returns true, so it can be comfortably invoked in an assert statement. * @throws \Error On bad input. */ protected function setPropAssert($name, ?\Closure $guard): bool { $this->__propAssertRequireDefined($name); $this->__propAssert[$name]['guard'] = $guard; return true; } // Internal method, don't invoke. public function __get($name) { $this->__propAssertRequireDefined($name); $isInternal = $this->__propAssertIsInternalCaller(); $prop = $this->__propAssert[$name]; return $this->__propAssert[$name]['value']; } // Internal method, don't invoke. public function __set($name, $value) { $this->__propAssertRequireDefined($name); $isInternal = $this->__propAssertIsInternalCaller(); $guard = $this->__propAssert[$name]['guard']; if (!$isInternal && !$guard) { throw new \TypeError('Cannot set read-only property ' . get_class($this) . '::$' . $name); } $result = $guard($value); if ($result === true) { $this->__propAssert[$name]['value'] = $value; } else { $details = is_string($result) ? ', expecting ' . $result : ''; throw new \TypeError('Invalid value for property ' . get_class($this) . '::$' . $name . $details); } } // Internal method, don't invoke. public function __isset($name) { $this->__propAssertRequireDefined($name); return $this->__propAssert[$name]['value'] === null; } // Internal method, don't invoke. public function __unset($name) { $this->__propAssertRequireDefined($name); throw new \TypeError('Cannot unset property ' . get_class($this) . '::$' . $name); } // Internal method, don't invoke. private function __propAssertRequireDefined($name) { if (!isset($this->__propAssert[$name])) { throw new \TypeError('Undefined property ' . get_class($this) . '::$' . $name); } } // Internal method, don't invoke. private function __propAssertIsInternalCaller() { // TODO: Relax this check, so static methods of the class and cross-object calls can skip checks? $object = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['object'] ?? null; return $this === $object; } } // -------------------------------------------------------------------------------------------------------------------- class Foo { use PropAssert; public $a = 10, $b = 20; function __construct() { $this->initPropAssert(); $this->setPropAssert('b', function ($v) { if (!is_int($v)) return 'an integer, you moran'; return true; }); } } $foo = new Foo(); echo $foo->a . PHP_EOL; echo $foo->b . PHP_EOL; $foo->b = 123; echo $foo->b . PHP_EOL; try { $foo->b = 'moran'; } catch (\Throwable $e) { echo $e->getMessage() . PHP_EOL; } try { $foo->a = 100; } catch (\Throwable $e) { echo $e->getMessage() . PHP_EOL; }

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.60.0090.00918.13
8.3.50.0060.00916.63
8.3.40.0100.00618.87
8.3.30.0040.01118.94
8.3.20.0040.00421.77
8.3.10.0090.00021.95
8.3.00.0040.00418.22
8.2.180.0120.00916.75
8.2.170.0140.00422.96
8.2.160.0100.00320.84
8.2.150.0040.00424.18
8.2.140.0040.01424.66
8.2.130.0000.00726.16
8.2.120.0080.00020.75
8.2.110.0060.00322.13
8.2.100.0120.00017.84
8.2.90.0030.00617.88
8.2.80.0000.00818.92
8.2.70.0000.00817.75
8.2.60.0030.00517.63
8.2.50.0040.00418.05
8.2.40.0040.00419.32
8.2.30.0000.00720.50
8.2.20.0000.00718.13
8.2.10.0030.00518.29
8.2.00.0040.00418.18
8.1.280.0090.00625.92
8.1.270.0080.00023.97
8.1.260.0040.00426.35
8.1.250.0090.00028.09
8.1.240.0000.00923.79
8.1.230.0040.00819.13
8.1.220.0000.00917.74
8.1.210.0000.00818.77
8.1.200.0060.00317.48
8.1.190.0060.00317.48
8.1.180.0030.00518.10
8.1.170.0000.00817.62
8.1.160.0080.00018.86
8.1.150.0050.00220.36
8.1.140.0000.00719.62
8.1.130.0030.00318.85
8.1.120.0070.00017.49
8.1.110.0030.00617.52
8.1.100.0040.00417.44
8.1.90.0030.00517.54
8.1.80.0040.00417.53
8.1.70.0030.00317.38
8.1.60.0030.00617.62
8.1.50.0000.00917.45
8.1.40.0000.00817.50
8.1.30.0000.00817.62
8.1.20.0040.00417.72
8.1.10.0040.00417.64
8.1.00.0040.00417.57
8.0.300.0070.00019.93
8.0.290.0040.00417.00
8.0.280.0040.00418.46
8.0.270.0040.00417.32
8.0.260.0030.00316.94
8.0.250.0040.00417.06
8.0.240.0070.00017.10
8.0.230.0040.00416.93
8.0.220.0000.00816.93
8.0.210.0000.00717.04
8.0.200.0030.00317.11
8.0.190.0040.00416.97
8.0.180.0070.00016.99
8.0.170.0000.00817.04
8.0.160.0030.00417.06
8.0.150.0000.00816.95
8.0.140.0060.00316.96
8.0.130.0040.00413.37
8.0.120.0050.00316.82
8.0.110.0000.00717.06
8.0.100.0000.00817.05
8.0.90.0050.00216.89
8.0.80.0100.01017.00
8.0.70.0030.00516.96
8.0.60.0040.00416.88
8.0.50.0040.00417.04
8.0.30.0150.00317.01
8.0.20.0110.01117.40
8.0.10.0000.00817.10
8.0.00.0070.01117.03
7.4.330.0020.00215.55
7.4.320.0050.00216.68
7.4.300.0030.00316.67
7.4.290.0030.00716.51
7.4.280.0030.00516.67
7.4.270.0000.00716.67
7.4.260.0110.00016.61
7.4.250.0040.00416.63
7.4.240.0040.00416.67
7.4.230.0000.00816.61
7.4.220.0140.00316.66
7.4.210.0070.00916.56
7.4.200.0040.00416.76
7.4.160.0160.00016.58
7.4.150.0120.00617.40
7.4.140.0060.01217.86
7.4.130.0000.01816.63
7.4.120.0110.01016.62
7.4.110.0110.00716.52
7.4.100.0120.00616.56
7.4.90.0120.00916.56
7.4.80.0150.01819.39
7.4.70.0170.00316.51
7.4.60.0060.01116.50
7.4.50.0080.00816.46
7.4.40.0000.01716.21
7.4.30.0050.01116.42
7.4.00.0100.00615.12
7.3.330.0030.00313.37
7.3.320.0000.00613.47
7.3.310.0030.00316.55
7.3.300.0070.00016.46
7.3.290.0090.00616.48
7.3.280.0060.01016.50
7.3.270.0140.00317.40
7.3.260.0120.00616.57
7.3.250.0120.00816.56
7.3.240.0110.00816.58
7.3.230.0110.00816.41
7.3.210.0090.00916.56
7.3.200.0170.00616.43
7.3.190.0150.00916.48
7.3.180.0060.01516.72
7.3.170.0150.00316.55
7.3.160.0060.00916.53
7.2.330.0090.00916.72
7.2.320.0070.01416.86
7.2.310.0070.01416.73
7.2.300.0040.01516.78
7.2.290.0090.00916.71
7.2.60.0070.00716.99
7.1.200.0100.00015.92
7.1.70.0050.00317.35
7.1.60.0730.00733.38
7.1.50.0530.01333.02
7.1.40.0470.01332.57
7.1.30.0400.01332.95
7.1.20.0500.01032.87
7.1.10.0430.00714.96
7.1.00.0630.01015.11
7.0.200.0370.01314.84
7.0.190.0500.00314.61
7.0.180.0270.01314.14
7.0.170.0300.00714.41
7.0.160.0330.01014.32
7.0.150.0400.01014.14
7.0.140.0370.00714.35
7.0.130.0470.00714.38
7.0.120.0600.01714.58
7.0.110.0330.01014.23
7.0.100.0330.01714.30
7.0.90.0400.00714.25
7.0.80.0370.00714.49
7.0.70.0770.01014.22
7.0.60.0330.00713.96
7.0.50.0430.00714.26
7.0.40.0430.00714.47
7.0.30.0330.01014.68
7.0.20.0370.01314.34
7.0.10.0530.01314.35
7.0.00.0370.00714.36

preferences:
54.13 ms | 400 KiB | 5 Q