3v4l.org

run code in 300+ PHP versions simultaneously
<?php trait CouldCheckMethods { private static array $couldBeCalled = []; public static function check(callable $method): void { if (!self::could($method)) { throw new BadMethodCallException( sprintf( '%s cannot be called. To call that method, method should have attribute `%s`', self::callableToString($method), static::class ) ); } } public static function could(callable $method): bool { $method = self::callableToString($method); if (!array_key_exists($method, self::$couldBeCalled)) { self::$couldBeCalled[$method] = self::checkMethod($method); } return self::$couldBeCalled[$method]; } private static function checkMethod(string $method): bool { try { if (PHP_MINOR_VERSION >= 3) { // This is because since 8.4 calling new RefMet() with 1 parametr is deprecated $reflection = ReflectionMethod::createFromMethodName($method); } else { // but createFromMethodName is not available before 8.3 $reflection = new ReflectionMethod($method); } } catch (ReflectionException) { return false; } return (bool) $reflection->getAttributes(static::class); } private static function callableToString(callable $method): string { if (is_array($method)) { return sprintf('%s::%s', is_object($method[0]) ? get_class($method[0]) : $method[0], $method[1]); } if ($method instanceof Closure) { return 'Closure'; } if (is_string($method)) { return $method; } if (is_object($method) && method_exists($method, '__invoke')) { return sprintf('%s::__invoke', $method::class); } throw new InvalidArgumentException('Unsupported callable type'); } } #[Attribute(Attribute::TARGET_METHOD)] class CouldCallStatically { use CouldCheckMethods; } #[Attribute(Attribute::TARGET_METHOD)] class CouldCallNonStatically { use CouldCheckMethods; } class MyClass { #[CouldCallNonStatically] #[CouldCallStatically] protected static function send(string $send) { var_dump([ 'We made it', $send ]); } #[CouldCallStatically] protected static function onlyWorkStatically(string $send) { var_dump([ 'Work only static', $send ]); } protected function stillProtected() { var_dump('This will failed, because of missing attribute'); } public function __call(string $name, array $arguments) { CouldCallNonStatically::check([$this, $name]); return $this::$name(...$arguments); } public static function __callStatic(string $name, array $arguments) { CouldCallStatically::check([self::class, $name]); return static::$name(...$arguments); } } $obj = new MyClass(); $obj->send('Non static call'); MyClass::send('Static call'); try { MyClass::onlyWorkStatically('Try only static call'); $obj->onlyWorkStatically('Oh that will failed'); } catch (Throwable $e) { var_dump($e->getMessage()); } try { $obj->stillProtected('Oh that will failed'); } catch (Throwable $e) { var_dump($e->getMessage()); } try { MyClass::stillProtected('Oh that will failed'); } catch (Throwable $e) { var_dump($e->getMessage()); }

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.5.10.0120.00616.75
8.5.00.0120.01020.36
8.4.150.0020.00014.05
8.4.140.0140.00717.64
8.4.130.0060.00322.28
8.4.120.0030.00522.48
8.4.110.0120.00822.55
8.4.100.0120.00917.86
8.4.90.0140.00720.60
8.4.80.0060.00220.72
8.4.70.0110.00919.07
8.4.60.0130.00717.87
8.4.50.0100.01019.69
8.4.40.0410.00918.07
8.4.30.0390.01017.87
8.4.20.0300.01817.77
8.4.10.0290.01117.59
8.3.280.0120.00818.45
8.3.270.0110.00916.53
8.3.260.0100.00416.87
8.3.250.0140.00618.95
8.3.240.0140.00517.38
8.3.230.0130.00716.77
8.3.220.0140.00419.17
8.3.210.0060.00216.83
8.3.200.0050.00416.55
8.3.190.0110.00818.41
8.3.180.0100.00816.84
8.3.170.0280.01816.77
8.3.160.0390.00816.68
8.3.150.0480.00016.45
8.3.140.0380.00716.82
8.3.130.0300.01116.77
8.3.120.0280.01416.58
8.3.110.0380.00016.50
8.3.100.0300.01116.77
8.3.90.0120.00916.48
8.3.80.0440.00416.77
8.3.70.0400.00616.74
8.3.60.0400.00316.61
8.3.50.0430.00316.68
8.3.40.0260.01417.43
8.3.30.0330.00717.47
8.3.20.0360.00417.36
8.3.10.0340.00717.34
8.3.00.0320.00717.38
8.2.290.0090.00916.75
8.2.280.0090.00918.26
8.2.270.0280.00916.70
8.2.260.0300.00916.68
8.2.250.0230.01616.57
8.2.240.0280.01216.60
8.2.230.0390.00616.61
8.2.220.0350.00716.39
8.2.210.0260.01516.66
8.2.200.0320.00716.48
8.2.190.0280.00616.79
8.2.180.0270.01016.46
8.2.170.0330.00917.94
8.2.160.0350.00917.66
8.2.150.0260.01517.32
8.2.140.0260.00717.38
8.2.130.0350.00717.43
8.2.120.0340.01017.60
8.2.110.0340.00017.71
8.2.100.0270.01317.67
8.2.90.0230.01717.65
8.2.80.0320.00417.59
8.2.70.0210.01217.58
8.2.60.0140.01017.71
8.2.50.0180.00017.62
8.2.40.0320.00617.76
8.2.30.0340.00317.63
8.2.20.0290.00817.31
8.2.10.0300.00717.71
8.2.00.0220.01317.64
8.1.320.0100.01015.97

preferences:
56.17 ms | 403 KiB | 5 Q