ray / aop
面向切面框架
Requires
- php: ^7.2 || ^8.0
- ext-hash: *
- ext-tokenizer: *
- doctrine/annotations: ^1.12 || ^2.0
- koriym/attributes: ^1.0.3
Requires (Dev)
- bamarni/composer-bin-plugin: ^1.4.1
- nikic/php-parser: ^4.16
- phpunit/phpunit: ^8.5.23 || ^9.5.10
Suggests
- ray/di: A dependency injection framework
- 2.x-dev
- 2.16.2
- 2.16.1
- 2.16.0
- 2.15.2
- 2.15.1
- 2.15.0
- 2.14.0
- 2.13.1
- 2.13.0
- 2.12.4
- 2.12.3
- 2.12.2
- 2.12.1
- 2.12.0
- 2.11.0
- 2.10.6
- 2.10.5
- 2.10.4
- 2.10.3
- 2.10.2
- 2.10.1
- 2.10.0
- 2.9.9
- 2.9.8
- 2.9.7
- 2.9.6
- 2.9.5
- 2.9.4
- 2.9.3
- 2.9.2
- 2.9.1
- 2.9.0
- 2.8.8
- 2.8.7
- 2.8.6
- 2.8.5
- 2.8.4
- 2.8.3
- 2.8.0
- 2.7.7
- 2.7.6
- 2.7.5
- 2.7.4
- 2.7.3
- 2.7.2
- 2.7.1
- 2.7.0
- 2.6.0
- 2.5.2
- 2.5.0
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.3
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.0
- 2.1.1
- 2.1.0
- 2.0.1
- 2.0.0
- 2.0.0-beta.3
- 2.0.0-beta.2
- 2.0.0-beta
- 2.0.0-alpha.3
- 2.0.0-alpha.2
- 2.0.0-alpha
- 1.x-dev
- 1.3.1
- 1.3.0
- 1.2.7
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.0
- dev-fix-typo
- dev-pecl
This package is auto-updated.
Last update: 2024-09-14 08:52:56 UTC
README
面向切面框架
Ray.Aop 包提供方法拦截。此功能使您能够编写在匹配的方法被调用时执行的代码。它适用于跨切面关注点("方面"),如事务、安全和日志记录。因为拦截器将问题划分为方面而不是对象,所以它们的使用称为面向切面编程(AOP)。
匹配器是一个简单的接口,它接受或拒绝一个值。对于 Ray.AOP,您需要一个匹配器:一个定义哪些类参与,另一个用于这些类的成员方法。为了使这变得简单,有一个工厂类来满足常见的场景。
方法拦截器在匹配的方法被调用时执行。它们有机会检查调用:方法、其参数和接收实例。它们可以执行它们的跨切面逻辑,然后委托给底层方法。最后,它们可以检查返回值或异常并返回。由于拦截器可以应用于许多方法并将接收许多调用,因此它们的实现应该是高效且不干扰的。
示例:禁止周末调用方法
为了说明方法拦截器如何与 Ray.Aop 一起工作,我们将禁止周末调用我们的披萨计费系统。快递员只在周一到周五工作,所以我们将在无法交付的情况下阻止订购披萨!这个例子在结构上类似于使用 AOP 进行授权。
为了标记选择的方法为仅工作日,我们定义一个属性。
<?php #[Attribute(Attribute::TARGET_METHOD)] final class NotOnWeekends { }
...并将其应用到需要被拦截的方法上
<?php class RealBillingService { #[NotOnWeekends] public function chargeOrder(PizzaOrder $order, CreditCard $creditCard) {
接下来,我们通过实现 org.aopalliance.intercept.MethodInterceptor 接口来定义拦截器。当我们需要调用底层方法时,我们通过调用 $invocation->proceed()
来实现。
<?php class WeekendBlocker implements MethodInterceptor { public function invoke(MethodInvocation $invocation) { $today = getdate(); if ($today['weekday'][0] === 'S') { throw new \RuntimeException( $invocation->getMethod()->getName() . " not allowed on weekends!" ); } return $invocation->proceed(); } }
最后,我们使用 Aspect
类配置一切
use Ray\Aop\Aspect; use Ray\Aop\Matcher; $aspect = new Aspect(); $aspect->bind( (new Matcher())->any(), (new Matcher())->annotatedWith(NotOnWeekends::class), [new WeekendBlocker()] ); $billing = $aspect->newInstance(RealBillingService::class); try { echo $billing->chargeOrder(); } catch (\RuntimeException $e) { echo $e->getMessage() . "\n"; exit(1); }
将所有这些放在一起(并等待周六),我们看到方法被拦截,我们的订单被拒绝
chargeOrder not allowed on weekends!
PECL 扩展
Ray.Aop 还支持PECL 扩展。当扩展被安装时,您可以使用 weave
方法将方面应用于目录中的所有类。
$aspect = new Aspect(); $aspect->bind( (new Matcher())->any(), (new Matcher())->annotatedWith(NotOnWeekends::class), [new WeekendBlocker()] ); $aspect->weave(__DIR__ . '/src'); // Weave the aspects to all classes in the directory that match the matcher. $billing = new RealBillingService(); echo $billing->chargeOrder(); // Interceptors applied
使用 PECL 扩展
- 您可以在代码的任何位置使用正常的
new
关键字创建新实例。 - 拦截器甚至可以在
final
类和方法中工作。
要使用这些功能,只需安装 PECL 扩展,Ray.Aop 将在可用时自动利用它。需要 PHP 8.1+ 以使用 PECL 扩展。
安装 PECL 扩展
要使用 PECL 扩展,需要 PHP 8.1 或更高版本。有关更多信息,请参阅ext-rayaop。
配置选项
在创建 Aspect
实例时,您可以可选地指定一个临时目录
$aspect = new Aspect('/path/to/tmp/dir');
如果没有指定,将使用系统默认的临时目录。
这总结了Ray.Aop的基本用法。有关更详细的信息和高级用法,请参阅完整文档。
自定义匹配器
您可以拥有自己的匹配器。要创建contains
匹配器,您需要提供一个包含两个方法的类。一个是用于类匹配的matchesClass
方法,另一个是用于方法匹配的matchesMethod
方法。两者都返回匹配结果的布尔值。
use Ray\Aop\AbstractMatcher; use Ray\Aop\Matcher; class IsContainsMatcher extends AbstractMatcher { /** * {@inheritdoc} */ public function matchesClass(\ReflectionClass $class, array $arguments) : bool { [$contains] = $arguments; return (strpos($class->name, $contains) !== false); } /** * {@inheritdoc} */ public function matchesMethod(\ReflectionMethod $method, array $arguments) : bool { [$contains] = $arguments; return (strpos($method->name, $contains) !== false); } }
拦截器详情
在拦截器中,将一个MethodInvocation
对象传递给invoke
方法。
class MyInterceptor implements MethodInterceptor { public function invoke(MethodInvocation $invocation) { // Before method invocation $result = $invocation->proceed(); // After method invocation return $result; } }
$invocation->proceed()调用链中的下一个拦截器。如果没有更多的拦截器,它将调用目标方法。这种链式调用允许对单个方法使用多个拦截器,并按照绑定顺序执行。
拦截器A、B和C的示例执行流程
- 拦截器A(之前)
- 拦截器B(之前)
- 拦截器C(之前)
- 目标方法
- 拦截器C(之后)
- 拦截器B(之后)
- 拦截器A(之后)
这种链式机制允许您将多个横切关注点(如日志记录、安全和性能监控)组合到单个方法中。
使用MethodInvocation
对象,您可以
$invocation->proceed()
- 调用方法$invocation->getMethod()
- 获取方法反射$invocation->getThis()
- 获取对象$invocation->getArguments()
- 获取参数$invocation->getNamedArguments()
- 获取命名参数。一个扩展的ClassRefletion
和MethodReflection
包含用于获取PHP 8属性和doctrine注解的方法。
/** @var $method \Ray\Aop\ReflectionMethod */ $method = $invocation->getMethod(); /** @var $class \Ray\Aop\ReflectionClass */ $class = $invocation->getMethod()->getDeclaringClass();
$method->getAnnotations()
- 获取方法属性/注解$method->getAnnotation($name)
- 获取方法属性/注解$class->->getAnnotations()
- 获取类属性/注解$class->->getAnnotation($name)
- 获取类属性/注解
注解/属性
Ray.Aop可以与PHP 7/8的doctrine/annotation或PHP 8的Attributes一起使用。
AOP联盟
Ray.Aop实现的拦截器API是称为AOP Alliance的公开规范的一部分。
安装
推荐通过Composer安装Ray.Aop。
# Add Ray.Aop as a dependency
$ composer require ray/aop ^2.0
PHP8属性仅(推荐)
SevericeLocator::setReader(new AttributeReader);`
集成DI框架
- 还可以查看集成了DI和AOP的DI框架Ray.Di。
技术信息
有关更详细的技术信息,请参阅以下资源
- 注意:本部分文档来自Guice/AOP。z1