Last active
September 22, 2023 09:41
-
-
Save SerafimArts/42a5de649de673fb569f6bfd96cc79ca to your computer and use it in GitHub Desktop.
PHP Decorators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
interface DecoratorInterface | |
{ | |
public static function handle(\Reflector $context, self $instance): void; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require __DIR__ . '/vendor/autoload.php'; | |
new StructureExample(); | |
// TypeError@anonymous: The structure class does not allow method StructureExample::method() to be declared in example\StructureExample.php:20 | |
// Stack trace: | |
// #0 example\PhpStruct.php(31): PhpStruct->error(Object(ReflectionMethod)) | |
// #1 example\PhpStruct.php(65): PhpStruct->assert(Object(ReflectionClass)) | |
// #2 example\interceptor.php(36): PhpStruct::handle(Object(ReflectionClass), Object(PhpStruct)) | |
// #3 example\example.php(11): {closure}('StructureExample') | |
// #4 {main} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
use Composer\Autoload\ClassLoader; | |
$composer = (static function (): ClassLoader { | |
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) ?? []; | |
while ($trace) { | |
$current = array_shift($trace); | |
if (str_starts_with($current['class'] ?? '', 'ComposerAutoloaderInit')) { | |
return $current['class']::getLoader(); | |
} | |
} | |
throw new LogicException('File ' . __FILE__ . ' MUST be loaded though composer'); | |
})(); | |
spl_autoload_register(static function (string $class) use ($composer) { | |
$composer->loadClass($class); | |
if (\class_exists($class, false)) { | |
$reflection = new \ReflectionClass($class); | |
foreach ($reflection->getAttributes(DecoratorInterface::class, \ReflectionAttribute::IS_INSTANCEOF) as $context) { | |
($context->getName())::handle($reflection, $context->newInstance()); | |
} | |
foreach ($reflection->getProperties() as $property) { | |
foreach ($property->getAttributes(DecoratorInterface::class, \ReflectionAttribute::IS_INSTANCEOF) as $context) { | |
($context->getName())::handle($property, $context->newInstance()); | |
} | |
} | |
foreach ($reflection->getMethods() as $method) { | |
foreach ($method->getAttributes(DecoratorInterface::class, \ReflectionAttribute::IS_INSTANCEOF) as $context) { | |
($context->getName())::handle($method, $context->newInstance()); | |
} | |
} | |
} | |
}, true, true); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
#[\Attribute] | |
class PhpStruct implements DecoratorInterface | |
{ | |
private const ERROR_METHOD = 'The structure class does not allow method %s::%s() to be declared'; | |
private function assert(\ReflectionClass $class): bool | |
{ | |
foreach ($class->getMethods() as $method) { | |
throw $this->error($method); | |
} | |
return true; | |
} | |
private function error(\ReflectionMethod $method): \TypeError | |
{ | |
$message = \sprintf(self::ERROR_METHOD, $method->getDeclaringClass()->getName(), $method->getName()); | |
return new class($message, $method) extends \TypeError { | |
public function __construct(string $message, \ReflectionMethod $ctx) | |
{ | |
parent::__construct($message); | |
$this->file = $ctx->getFileName(); | |
$this->line = $ctx->getStartLine(); | |
} | |
}; | |
} | |
public static function handle(\Reflector $context, DecoratorInterface $instance): void | |
{ | |
assert($instance instanceof self); | |
$instance->assert($context); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
#[PhpStruct] | |
class StructureExample | |
{ | |
public string $field; | |
// Struct (data-class) can not contain methods | |
public function method() | |
{ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment