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()); }
Output for 8.1.32, 8.2.0 - 8.2.29, 8.3.0 - 8.3.28, 8.4.1 - 8.4.14, 8.5.0 - 8.5.1
array(2) { [0]=> string(10) "We made it" [1]=> string(15) "Non static call" } array(2) { [0]=> string(10) "We made it" [1]=> string(11) "Static call" } array(2) { [0]=> string(16) "Work only static" [1]=> string(20) "Try only static call" } string(120) "MyClass::onlyWorkStatically cannot be called. To call that method, method should have attribute `CouldCallNonStatically`" string(116) "MyClass::stillProtected cannot be called. To call that method, method should have attribute `CouldCallNonStatically`" string(113) "MyClass::stillProtected cannot be called. To call that method, method should have attribute `CouldCallStatically`"
Output for 8.4.15
/bin/php-8.4.15: /usr/lib/libm.so.6: version `GLIBC_2.38' not found (required by /bin/php-8.4.15) /bin/php-8.4.15: /usr/lib/libm.so.6: version `GLIBC_2.35' not found (required by /bin/php-8.4.15) /bin/php-8.4.15: /usr/lib/libc.so.6: version `GLIBC_2.34' not found (required by /bin/php-8.4.15) /bin/php-8.4.15: /usr/lib/libc.so.6: version `GLIBC_2.38' not found (required by /bin/php-8.4.15)
Process exited with code 1.

preferences:
83.35 ms | 408 KiB | 5 Q