ejsmont-artur / php-proxy-builder
PHP代理构建器 - AOP启发的代理模式库。
0.1.4
2013-03-23 13:45 UTC
Requires
- php: >=5.3.0
This package is not auto-updated.
Last update: 2024-09-14 17:00:46 UTC
README
库允许您在任意类实例周围添加代理对象,以在运行时添加行为。
库采用了面向方面编程的概念,其中某些逻辑(如缓存)可以在应用程序中重用,而不必将应用程序代码耦合到缓存实现中。
主要功能
- 在运行时创建代理实例。
- 代理使用Advice实例(例如CachingAdvice)为代理对象添加行为。
- 代理实例将方法调用委派给原始(代理)对象。
- 代理、Advice和代理类是完全解耦的。代理不知道它所代理的是什么,也不知道Advice的目的。Advice不关心它是如何被使用的,并且它可以用于任何目标类。最重要的是,客户端代码不需要知道任何代理的存在。它消费代理就像它是目标实例本身一样。代理对客户端是透明的。
示例
<?php
// target instances to be proxied
$target = new SlowService();
// Advice implementing additional logic.
// We will integrate with frameworks to obtain $cacheBackendAdapter from your framework of choice like symfony2.
$advice = new CachingAdvice($cacheBackendAdapter);
$factory = new MagicMethodBasedFactory();
$proxiedService = $factory->createProxy($advice, $target);
// Call is made directly on the object, it's slow.
$target->getSomeData(12345);
// Calls are made through the proxy, which delegates to the CachingAdvice and then to target instance.
// First call is slow, the second call is fast as it is being cached.
$proxiedService->getSomeData(12345);
$proxiedService->getSomeData(12345);
未来实现
现在您可以看到的代码具有完整的测试覆盖率,但它只是库的第一个实现。
当前的实现基于魔术方法。因此,代理既不继承也不扩展代理对象,因此它不会通过类型提示检查或instanceof检查。
在不久的将来,我们将提供第二个实现,它将允许您从任何对象创建一个完全基于接口的代理。这样,代理将完全可互换于目标实例,并且可以通过类型检查
<?php
($proxiedService instanceof SlowService) == true;
($proxiedService instanceof CachingAdvice) == false;
更多示例
请查看单元测试,以了解代码应该如何使用和组装的更多示例。
包含的Advice
通过提供简单而实用的Advice实现,库获得了许多价值。我们决定将所有外部依赖项都排除在库的核心之外,因此我们不需要记录器或缓存实现。我们将与框架集成,在Adapter文件夹中提供我们最小化接口的实现。
- CachingAdvice - 为任意对象添加缓存。使用类名、方法名和参数作为缓存键。
- CircuitBreakerAdvice - 在对象周围添加断路器,以便在不可用的时候快速失败。
- InstrumentationAdvice - 计数方法调用并测量执行时间以进行监控和绘图。
- ClosureAdvice - 允许您使用闭包而不是完整的AroundAdviceInterface实现。
- LoggingAdvice - 记录所有方法调用以及时间,可选地记录参数/结果。
图表
请见下面的两个序列图,其中想象中的客户端在目标对象上调用“doSomething()”方法。
请注意,Advice对象独立于客户端和目标。它可以被替换和测试,而不需要对客户端或目标代码进行任何更改。
无代理的图表
有代理的图表
注释
- 代理对象没有以任何方式被修改,它只是被使用。
- 您可以代理任何现有的PHP对象。
- 被代理的对象可以调用其自身的方法,这些调用不会通过代理进行。这取决于你如何看待它,可以被认为是好事也可以是坏事。如果你想要针对如安全之类的功能选择性地代理方法,这会成为一个问题。你可以想象开发者可能会更改底层代码,将调用从不太安全的方法委托给更安全的方法,而代理将没有机会拦截。另一方面,你可以完全了解发生了什么,并且库非常轻量级,它不会修改现有代码。
- 如果你想要严格的AOP(面向切面编程),你可能需要考虑类加载时织入,这在类首次加载时修改类。然后你可以获得完整的方法拦截,因为类创建的实例已经内嵌了代理。查看https://github.com/lisachenko/go-aop-php,它看起来很有希望(不确定是否已准备就绪用于生产环境)。
- 性能是一个重要的因素,我们将提供基准测试并确保代码不会减慢整体执行速度。
运行测试
测试是通过PHPUnit运行的,如果你想要运行测试,则假定你已经安装了phpunit。你可以使用ant运行测试,"ci"目标会生成文档和代码覆盖率报告。
你可以使用以下任何命令来运行所有测试
ant
ant phpunit
ant ci
你可以通过运行以下命令来运行选定的测试用例
cd tests
phpunit Unit/PhpProxyBuilder/Aop/ClosureAdviceTest.php
贡献者
- Artur Esjmont (https://github.com/ejsmont-artur)
- Shawn Murphy (https://github.com/seguer)