zlikavac32 / nsb-decorators
即时装饰器
Requires
- php: ^7.4
- php-ds/php-ds: ^1.2
Requires (Dev)
- phpunit/phpunit: ^8.0
Suggests
- ext-ds: For native php-ds/php-ds support
This package is auto-updated.
Last update: 2024-09-29 05:28:21 UTC
README
即时服务装饰器。
目录
简介
最好从示例开始,让我们这么做。
假设我们有一个命令的接口。它可以运行,就这些。
interface Command { public function run(Input $input, Output $output): int; }
但是,根据应用程序的实现,命令可以做更多的事情。例如,命令可以有一个与之关联的帮助文本。
interface CommandWithHelp extends Command { public function help(): string; }
由于我们面向接口,装饰器很常见。可能会提供一个使用装饰的调试输出的装饰器。这样,根据我们如何构建我们的命令,我们会得到不同的行为。
class DebugCommand implements Command { private $command; public function __construct(Command $command) { $this->command = $command; } public function run(Input $input, Output $output): int { return $this->command->run($input, new DebugOutput($output)); } }
但我们现在有一个问题。因为装饰器不一定实现了具体命令的所有接口,我们可能会丢失一些功能。
class FoOCommand implements CommandWithHelp { public function run(Input $input, Output $output): int { $output->writeln('Foo'); return 0; } public function help(): string { return 'Command just writes Foo'; } } $command = new DebugCommand(new FooCommand()); $command->help(); // does not work
一个解决方案是将所有额外的接口合并到原始接口中,但这现在强加了大量的方法实现,尽管它们并不需要。我们会回到起点。
另一种方法可能是手动为相同的装饰器定义额外的实现,但这会引入太多新的类。
更好的方法可能是以编程方式实现。这正是这个库所做的。对于给定的装饰器类和主题类(被装饰实例的类),会创建新的代理装饰器类的代码。
安装
推荐通过 Composer 安装。
composer require zlikavac32/nsb-decorators
使用
要为代理装饰器类创建代码,使用 \Zlikavac32\NSBDecorators\Proxy::createClassProxy()
。它需要四个参数
代理 FQN
- 将生成的类的完全限定名装饰器
- 装饰器类的ReflectionClass
主题
- 被装饰的主题类的ReflectionClass
参数名称
- 接受主题服务的参数名称,不带$
然后可以将该代码存储在某个地方或评估。
也可以与自动加载器一起使用。使用 \Zlikavac32\NSBDecorators\Proxy::createFQNForProxyClass()
创建代理类名。它接受三个参数,装饰器类、主题类和装饰器类中接受主题的参数名称。类名编码了所有这些参数。
\Zlikavac32\NSBDecorators\Proxy::loadFQN
可以注册为自动加载器以在即时创建代理服务。
它是如何工作的?
收集了两个类中的接口,并计算了差异。代理类将扩展装饰器类,并实现主题实现的接口,而装饰器没有实现的接口。这些方法将只是代理到主题实例。
对于上面的示例,可能会生成类似这样的内容。
namespace Zlikavac32\NSBDecorators\Proxy { class Generated_4465627567436f6d6d616e64_466f4f436f6d6d616e64_636f6d6d616e64 extends \DebugCommand implements \CommandWithHelp { private $command; public function __construct(\Command $command) { parent::__construct($command); $this->command = $command; } public function help(): string { return $this->command->help(); } } }
要生成多个装饰器,链中的每个装饰器都必须以相同的方式生成(如果它还没有所需的接口)。
限制
此库旨在用于没有流畅接口的服务装饰器。
不支持静态方法、抽象类和匿名类。出于明显的原因,也不支持最终类。
依赖于未在方法声明中指定的参数的方法被忽略。目前参数是直接映射的。也许将来可能会使用 ...func_get_args()
。
示例
您可以在示例中看到带有代码注释的更多示例。