栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > PHP

php 的 AOP

PHP 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

php 的 AOP

6.2 PHP实践 

目前的PHP来说,还没有一个完整的AOP内置实现,虽然出现了RunKit,但一直都以BETA的状态呆在PECL项目里,估计很长时间内不太可能成为PHP的缺省设置。那是不是AOP在PHP里就破灭了呢?当然不是,因为我们有__get(),__set(),__call()等魔术方法,合理使用这些方法可以为我们实现某种程度的“准AOP”能力,之所以说是准AOP,是因为单单从实现上来看,称其为AOP有些牵强,但是从效果上来看,又部分实现了AOP的作用,虽然其实现方式并不完美,但对于一般的使用已经足够了。

  1.   

  2. class Target  

  3. {  

  4.     public function foobar(){  

  5.         echo '业务逻辑';  

  6.     }  

  7. }  

  8.   

  9. //业务逻辑类的包装类  

  10. class AOP  

  11. {  

  12.     private $instance;  

  13.   

  14.     public function __construct($instance) {  

  15.         $this->instance = $instance;  

  16.     }  

  17.   

  18.     public function __call($method, $param) {  

  19.         if(! method_exists($this->instance, $method)) {  

  20.             throw new Exception("Call undefinded method ".get_class($this->instance)."::$method");  

  21.         }  

  22.           

  23.         //前增强  

  24.         $this->before();  

  25.         $callBack = array($this->instance, $method);  

  26.         $return = call_user_func_array($callBack, $param);  

  27.         $this->after();  

  28.         return $return;  

  29.     }  

  30.       

  31.     public function  before() {  

  32.         echo '权限检查';  

  33.     }  

  34.       

  35.     public function after() {  

  36.         echo '日志记录';  

  37.     }  

  38. }  

  39.   

  40.   

  41.   

  42. class Factory  

  43. {  

  44.     public function getTargetInstance(){  

  45.         return new AOP(new Target());  

  46.     }  

  47. }  

  48.   

  49. //客户端调用演示  

  50. header("Content-Type: text/html; charset=utf8");  

  51. try {  

  52.     $obj = Factory::getTargetInstance();  

  53.     $obj->foobar();  

  54. } catch(Exception $e) {  

  55.     echo 'Caught exception: ',  $e->getMessage();  

  56. }  


利用php5内置的魔术方法__call来实现AOP,唯一的缺点是要在AOP类里面实例客户端对象,返回的是被AOP包装后的对象。因此像get_class会遇到麻烦。

比如说,客户端通过getBizInstance()方法以为得到的对象是Target,但实际上它得到的是一个Target的包装对象AOP,这样的话,如果客户端进行一些诸如get_class()之类和对象类型相关的操作就会出错,当然,大多数情况下,客户端似乎不太会做类似的操作。

其实我们在代理模式也提到过,这其实就是一个动态代理模式。

我们用 runkit 扩展来实现方法调用拦截的例子:

  1.   

  2. class Target  

  3. {  

  4.     public function foobar(){  

  5.         echo '业务逻辑';  

  6.     }  

  7. }  

  8. runkit_method_rename('Target', 'foobar', '#foobar');  

  9. runkit_method_add('Target','add','$a,$b','  

  10.     echo "before calln";  

  11.     $ret = $this->{"#foobar"}($a,$b);  

  12.     echo "after calln";  

  13.     return $ret;  

  14. ');  

也有人用了继承方式来实现:

  1.   

  2.   

  3. //业务逻辑类的包装类  

  4. class AOP  

  5. {  

  6.     private $instance;  

  7.   

  8.     public function __construct() {  

  9.     }  

  10.   

  11.     public function __call($method, $param) {  

  12.         if(strchr($method,'Aop_')){  

  13.             $method = str_replace('Aop_','',$method);  

  14.              if(! method_exists($this, $method)) {  

  15.                 throw new Exception("Call undefinded method ".get_class($this)."::$method");  

  16.             }  

  17.         }  

  18.         //前增强  

  19.         $this->before();  

  20.         $callBack = array($this, $method);  

  21.         $return = call_user_func_array($callBack, $param);  

  22.         $this->after();  

  23.         return $return;  

  24.     }  

  25.       

  26.     public function  before() {  

  27.         echo '权限检查';  

  28.     }  

  29.       

  30.     public function after() {  

  31.         echo '日志记录';  

  32.     }  

  33. }  

  34.   

  35.   

  36.   

  37. class Target extends AOP   

  38. {  

  39.     public function foobar(){  

  40.         echo '业务逻辑';  

  41.     }  

  42. }  

  43.   

  44.   

  45. //客户端调用演示  

  46. header("Content-Type: text/html; charset=utf8");  

  47. try {  

  48.     $obj = new  Target();  

  49.     $obj->Aop_foobar();  

  50. } catch(Exception $e) {  

  51.     echo 'Caught exception: ',  $e->getMessage();  

  52. }  

这个有明显的缺点:

1)严格的限制,如需要增强的方法名需要加AOP前缀。
2)如果Target类已经继承另外的父类,无法在继承AOP类。
3) AOP的实现,一个很重要的前提就是不能对源代码有很明显的侵入,而这里增强的目标对象要继承AOP类,无疑侵入了对象.

     除了以上的实现方法,我们可以使用配置文件来配置把哪些关注点代码增强到目标对象的切入点上。


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/229767.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号