不需要任何 PECL 扩展的纯 PHP 中的 AOP(Go!)- 怎么样?
AOP in plain PHP that doesn't require any PECL-extentions (Go!) - How?
有一个框架叫做Go! Aspect-Oriented Framework for PHP
它是用普通的 PHP 制作的,不需要任何 PECL 扩展和 DI 容器即可工作。
更重要的是可以与任何现有的 PHP 框架和库集成(有或没有额外配置)。
并且没有切入点的运行时检查,没有运行时注释解析,没有 evals 和 __call 方法,没有慢速代理和 call_user_func_array()。快速引导过程(2-20 毫秒)和建议调用。
所以我印象非常深刻,但我想知道的是,它实际上是如何工作的?
我在这里列出的这些要点...
我查看了 github 和官方网站以及其他一些文章,但找不到任何关于它如何工作的具体信息(一般和具体)。
我非常想知道它是如何工作的?它是如何实施的?
这个框架使用了很多隐藏的技巧来完成它的工作,但是如果我们从鸟瞰的角度来看,那么过程可以描述如下:
- 当前版本的 AOP 引擎旨在与作曲家紧密合作,因此它使用自己的代理包装作曲家加载器。从那时起,AOP 知道应该加载哪个 class 以及在哪里寻找它的源代码。
- 当某些 class
Foo
从文件 Foo.php
加载时,AOP 将其包装到特殊的过滤流中,如下所示:include 'php://filter/read=go.source.transforming.loader/resource=Foo.php';
。您可以在 'php://stream' manual 阅读有关此流过滤器的更多信息
- 此时,class 还没有加载到 PHP 内存中,但是框架已经知道它的内容并且可以对源代码进行分析甚至修改。
- 源代码然后标记化,通过 nikic/PHP-Parser library and then static reflection of this code is generated (still without loading this file into PHP's memory) via goaop/parser-reflection
解析为 AST
- 引擎从方面检查所有注册的切入点并执行原始 class
Foo
的转换:它被重命名为 Foo__AopProxied
和新文件 class Foo extends Foo__AopProxied
在缓存中生成。
- 引擎然后指示自动加载器从那个新文件而不是原始文件加载这个 class,所以你有你原来的 class 名称,但有来自建议的附加逻辑。看起来像是在运行时自动生成装饰器。
当然,这只是少量信息,因为在纯 PHP 中实现 AOP 是一项非常艰巨的任务,在发现可行的解决方案之前我尝试了很多次,因此深入研究源代码会很有趣发现隐藏宝石的代码:) 我的 PhpSerbia talk about cross-cutting concerns in PHP 中也提供了一些信息,您可以观看它以更好地理解(对不起我的英语)。
此外,我们目前正在为框架编写文档,所以如果您想改进它,请向我们发送 PR 至 official documentation。
您还应该使用 PhpStorm 插件,它为在 PHP 个项目中使用 AOP 的开发人员提供了许多功能。
有一个框架叫做Go! Aspect-Oriented Framework for PHP
它是用普通的 PHP 制作的,不需要任何 PECL 扩展和 DI 容器即可工作。
更重要的是可以与任何现有的 PHP 框架和库集成(有或没有额外配置)。
并且没有切入点的运行时检查,没有运行时注释解析,没有 evals 和 __call 方法,没有慢速代理和 call_user_func_array()。快速引导过程(2-20 毫秒)和建议调用。
所以我印象非常深刻,但我想知道的是,它实际上是如何工作的?
我在这里列出的这些要点...
我查看了 github 和官方网站以及其他一些文章,但找不到任何关于它如何工作的具体信息(一般和具体)。
我非常想知道它是如何工作的?它是如何实施的?
这个框架使用了很多隐藏的技巧来完成它的工作,但是如果我们从鸟瞰的角度来看,那么过程可以描述如下:
- 当前版本的 AOP 引擎旨在与作曲家紧密合作,因此它使用自己的代理包装作曲家加载器。从那时起,AOP 知道应该加载哪个 class 以及在哪里寻找它的源代码。
- 当某些 class
Foo
从文件Foo.php
加载时,AOP 将其包装到特殊的过滤流中,如下所示:include 'php://filter/read=go.source.transforming.loader/resource=Foo.php';
。您可以在 'php://stream' manual 阅读有关此流过滤器的更多信息
- 此时,class 还没有加载到 PHP 内存中,但是框架已经知道它的内容并且可以对源代码进行分析甚至修改。
- 源代码然后标记化,通过 nikic/PHP-Parser library and then static reflection of this code is generated (still without loading this file into PHP's memory) via goaop/parser-reflection 解析为 AST
- 引擎从方面检查所有注册的切入点并执行原始 class
Foo
的转换:它被重命名为Foo__AopProxied
和新文件 classFoo extends Foo__AopProxied
在缓存中生成。 - 引擎然后指示自动加载器从那个新文件而不是原始文件加载这个 class,所以你有你原来的 class 名称,但有来自建议的附加逻辑。看起来像是在运行时自动生成装饰器。
当然,这只是少量信息,因为在纯 PHP 中实现 AOP 是一项非常艰巨的任务,在发现可行的解决方案之前我尝试了很多次,因此深入研究源代码会很有趣发现隐藏宝石的代码:) 我的 PhpSerbia talk about cross-cutting concerns in PHP 中也提供了一些信息,您可以观看它以更好地理解(对不起我的英语)。
此外,我们目前正在为框架编写文档,所以如果您想改进它,请向我们发送 PR 至 official documentation。
您还应该使用 PhpStorm 插件,它为在 PHP 个项目中使用 AOP 的开发人员提供了许多功能。