本文实例讲述了ThinkPHP5 框架引入 Go AOP,PHP AOP编程。分享给大家供大家参考,具体如下:
项目背景
目前开发的WEB软件里有这一个功能,PHP访问API操作数据仓库,刚开始数据仓库小,没发现问题,随着数据越来越多,调用API时常超时(60s)。于是决定采用异步请求,改为60s能返回数据则返回,不能则返回一个异步ID,然后轮询是否完成统计任务。由于项目紧,人手不足,必须以最小的代价解决当前问题。
方案选择
- 重新分析需求,并改进代码
- 采用AOP方式改动程序
从新做需求分析,以及详细设计,并改动代码,需要产品,架构,前端,后端的支持。会惊动的人过多,在资源紧张的情况下是不推荐的。
采用AOP方式,不改动原有代码逻辑,只需要后端就能完成大部分任务了。后端用AOP切入请求API的方法,通过监听API返回的结果来控制是否让其继续运行原有的逻辑(API在60s返回了数据),或者是进入离线任务功能(API报告统计任务不能在60s内完成)。
之前用过AOP-PHP
拓展,上手很简单,不过后来在某一个大项目中引入该拓展后,直接爆了out of memory
,然后就研究其源码发现,它改变了语法树,并Hook了每个被调用的方法,也就是每个方法被调用是都会去询问AOP-PHP
,这个方法有没有切面方法。所以效率损失是比较大的。而且这个项目距离现在已经有8年没更新了。所以不推荐该解决方案。
实际环境
Debian,php-fpm-7.0,ThinkPHP-5.10。
引入AOP
作为一门zui好的语言,PHP是不自带AOP的。那就得安装AOP-PHP拓展,当我打开pecl要下载时,傻眼了,全是bate版,没有显示说明支持php7。但我还是抱着侥幸心理,找到了git,发现4-5年没更新了,要不要等一波更新,哦,作者在issue里说了有时间就开始兼容php7。
好吧,狠话不多说,下一个方案:Go!AOP.看了下git,作者是个穿白体恤,喜欢山峰的大帅哥,基本每个issue都会很热心回复。
composer require goaop/framework
ThinkPHP5 对composer兼容挺不错的哦,(到后面,我真想揍ThinkPHP5作者)这就装好了,怎么用啊,git上的提示了简单用法。我也就照着写了个去切入controller。
<"htmlcode"><"execution(public|protected app\tests\controller\Test1->aspectAction(*))") */ public function beforeMethodExecution(MethodInvocation $invocation) { $obj = $invocation->getThis(); echo 'Calling Before Interceptor for method: ', is_object($obj) "<br>\n"; } }启用aspect
<"htmlcode"><"htmlcode"><"color: #0000ff">http://127.0.0.1/tests/test1/test1 显示:hello这不是预期的效果,在aspect定义了,访问该方法前,会输出方法的更多信息信息。
像如下内容才是预期Calling Before Interceptor for method: app\tests\controller\Test1->aspectAction() with arguments: []
上他官方Doc看看,是一些更高级的用法。没有讲go-aop的运行机制。
上git上也没看到类似issue,额,发现作者经常在issue里回复:试一试demo。也许我该试试demo。Run Demos
我采用的是LNMP技术栈。
- 假设这里有台Ubuntu你已经配置好了LNMP环境
- 下载代码
- 配置nginx
# file: /usr/share/etc/nginx/conf.d/go-aop-test.conf server { listen 8008; # listen 443 ssl; server_name 0.0.0.0; root "/usr/share/nginx/html/app/vendor/lisachenko/go-aop-php/demos"; index index.html index.htm index.php; charset utf-8; access_log /var/log/nginx/go-aop-access.log; error_log /var/log/nginx/go-aop-error.log notice; sendfile off; client_max_body_size 100m; location ~ \.php(.*)$ { include fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param PATH_INFO $fastcgi_path_info; # fastcgi_param SCRIPT_FILENAME /var/www/html/app/vendor/lisachenko/go-aop-php/demos$fastcgi_script_name; #docker的配置 fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/api/vendor/lisachenko/go-aop-php/demos$fastcgi_script_name; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_split_path_info (("color: #0000ff">http://127.0.0.1:8008 试试,(估计大家都遇到了这个)
- 这个报错信息提示找不到这个类。来到报错的文件里。这文件使用了use找不到类,就是autoload出问题了,看到
vendor/lisachenko/go-aop-php/demos/autoload.php
这个文件。<"htmlcode"><"" src="/UploadFiles/2021-04-02/202051291211201.png">
尝试了下,运行成功
通过以上的输出,可以得出demo里是对方法运行前成功捕获。为什么在thinkphp的controller里运行就不成功呢。我决定采用断点进行调试。
通过断点我发现了这个文件
<"劫持" composer autoload 让每个类都进过它,根据aspect的定义来决定是否为其创建一个代理类,并植入advice。
额,ThinkPHP5是把composer autoload里的东西copy出来,放到自己autoload里,然后就没composer啥事了。然后go-aop一直等不到composer autoload下发的命令,自然就不能起作用了,so,下一步改进ThinkPHP5
在ThinkPHP5里,默认有且只会注册一个TP5内部的 Loader,并不会把include请求下发给composer的autoload。所以,为其让go-aop起作用,那么必须让让include class的请求经过 AopComposerLoad.
我们看看这个文件<"nofollow noreferrer" target="_blank" href="http://php.net/manual/zh/function.spl-autoload-register.php">spl_autoload_register 函数的第三个参数prepend
设置为true,就能让其排在在TP5的loader前面,先一步被调用。依照如上原理,就可以做如下改进
这个是为go-aop包装的新autoload,本质上是在原来的ThinkPHP5的loader上加了一个壳而已。<"htmlcode"><"color: #0000ff">http://127.0.0.1/tests/test1/test1 你就能看到来自aspect
输出的信息了。
最后我们做个总结:
PHP7
目前没有拓展实现的AOP
。ThinkPHP5
有着自己的Autoloader
。Go!AOP
的AOP实现依赖Class Autoload
的callback
,通过替换原文件
指向Proxy类
实现。ThinkPHP5
整合Go!AOP
需要调整autoload
。更多关于thinkPHP相关内容感兴趣的读者可查看本站专题:《ThinkPHP入门教程》、《thinkPHP模板操作技巧总结》、《ThinkPHP常用方法总结》、《codeigniter入门教程》、《CI(CodeIgniter)框架进阶教程》、《Zend FrameWork框架入门教程》及《PHP模板技术总结》。
希望本文所述对大家基于ThinkPHP框架的PHP程序设计有所帮助。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com桃源资源网 Design By www.nqtax.com暂无“ThinkPHP5 框架引入 Go AOP,PHP AOP编程项目详解”评论...