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

PHP注释AOP的实现

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

PHP注释AOP的实现

    AOP是时下比较流行的一种编程思想,它为程序的解耦带来了进一步的发展。在出现AOP的应用之前,我们如果需要在每个程序执行前或执行后记录LOG,在执行每个代码前进行用户访问控制,就不得不重复的显式调用同一个方法。如

public void anyfunc(){
    createLog();
    
}

public void anyfunc(){
    if(RBAC::access()){
        
    }
}

    这些“方面”的代码会显式的存在与每个需要它的方法中,与业务代码形成了紧耦合的关系。而AOP的出现解决了固定需求的代码与普通的业务代码之间的隔离。为程序提供了更高的可扩展性与可修改性,更加符合面向对象编程的原则。在现今流行的应用于WEB开发的语言中,Java通过动态代理技术原理可以很好的实现AOP的思想。Python也可以通过@修饰符来实现AOP。而PHP确不能通过语言本身的特性来实现AOP的需求。

    对于PHP先天性的弱势,许多PHP框架也采取了一些措施,如Yii框架提供了beforeControllerAction与afterControllerAction方法,支持代码执行时的before与after操作。但与JAVA以注释的实现方式相比,还是缺少了一定的灵活性。那么PHP能不能也通过注释的方式来实现AOP呢?之前我一直认为除非PHP的语言特性支持,否则要想通过注释的方式来实现AOP是不可能的。但当我在一次工作中接触到一款名为OpenCart的开源电子商店的代码后,受到了一点启发。其实,我们完全可以通过重写页面的方法来“实现”注释方式的AOP呀。下面,我将以自己做的一个demo样本,与大家一起探讨下PHP的”注释AOP“实现,希望能对大家有一个启发。此段demo是在Yii框架下实现的,里面还有一些问题需要进行优化和完善。

    首先给出此方法的一个逻辑流程:


      思想很简单,就是根据注释,按照一定规则生成新的代码文件,然后让程序执行新生成的文件代码。由于每次操作都需要生成新的文件,这样对程序的执行效率会产生一定的影响,所以我们可以考虑按一定的策略来生成新文件,比如按照文件的修改时间来生成新文件,在执行相应操作时先判断controller文件有无修改,如果无修改,则读取上次生成的文件执行,如在上次执行的间隔时间中,controller文件有修改,则生成新的文件。


    在样例中,我们主要支持before和after的操作,before是在controller方法执行前执行,after是在controller方法执行后执行。举个例子,有以下代码:

        public function logic(){
            echo 'Hello World';
        }


    那么在执行logic()方法时,会先执行Logger类的createlog方法记录log,log方法不会渗透到logic()方法的实体内,而是以注释的方式存在。下面我们就来看看实现这项需求的具体代码。代码实现步骤:


    一、找到CWebApplication.php文件,它的位置是frameworkwebCWebApplication.php。添加parseClassFile方法用来解析原有的Controller类,代码如下:

            public function parseClassFile($id,$aopconfigpath){
              $className=ucfirst($id).'Controller';
              $classFile=$this->getControllerPath().DIRECTORY_SEPARATOR.$className.'.php';
              if(!is_file($classFile)){
                   return false;
              }
              $originalContent = file_get_contents($classFile);
     //获取原始Controller的内容
              $mark_patten = '//s';
              $mark_patten1 = '/(|)/s';
              $mark_patten2 = '/([^d]|[^d])/s';
              preg_match_all($mark_patten1, $originalContent,$mark,PREG_OFFSET_CAPTURE);
              if(empty($mark[0])){
                   return $originalContent;
    //如果没有找到相关的AOP注释,则直接返回原始内容
              }
              $newContent = $originalContent;
 //以下是具体解析注释的过程
              foreach($mark[0] as $k=>$m){
               if($k!=0){
                    preg_match_all($mark_patten2, $newContent,$submark,PREG_OFFSET_CAPTURE);
                    $m[1] = $submark[0][0][1];
                    $m[0] = $submark[0][0][0];
               }
               $front_part = substr($newContent,0,$m[1]);
               $behind_part = substr($newContent,$m[1]+strlen($m[0]));
               $replace_part = preg_replace('/s+/', '', $m[0]).$m[1];
               $exact_pattens[] = $replace_part;
               $newContent = $front_part.$replace_part."n".$behind_part;
               }
          foreach($exact_pattens as $k=>$exact_patten){
           $exact_patten = addcslashes($exact_patten,'的注释。在实际的用户请求中,就会在执行相应的controller方法前或后(取决于注释的关键字是before还是after)执行切面类的方法了。

        

    虽然通过代码重构的技术,可以实现PHP的注释AOP功能,但此种方法也有一些缺点,如I/O操作带来的性能消耗。当Controller文件占用空间较大时,会对执行工作效率产生严重的影响。另外如果要让注释支持更多的功能,则需要提供更为复杂的解析方式,解析是通过正则表达式与替换、字符串查找方式来进行的,而这些操作对系统的性能也有一定影响。所以在进行解析时应尽量避免内嵌循环遍历等操作。样例中的代码还有许多地方需要修改和优化,希望此篇文章能为大家起到抛砖引玉的作用。

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

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

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