zoukankan      html  css  js  c++  java
  • PHP-AOP简介

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。

    AOP-PHP是一个PECL扩展,您可以在PHP中使用面向方面的编程,无需编译或进行其他任何中间步骤。

    AOP扩展的设计是最简单的方法,你可以认为PHP中的aop实现。

    AOP旨在让横切关注点的分离(缓存,日志,安全,交易,……)

    有两种安装模式:

    第一种方法:

    sudo pecl install aop-beta  

    第二种方法:

    #Clone the repository on your computer
        git clone https://github.com/AOP-PHP/AOP
        cd AOP
        #prepare the package, you will need to have development tools for php
        phpize
        #compile the package
          ./configure --with-aop --with-php-config=/usr/bin/php-config 
    
        make
        #before the installation, check that it works properly
        make test
        #install
        make install

    第二种方法安装中可能出现的错误:

    Can't locate Autom4te/C4che.pm in @INC (@INC contains: /usr/local/share/autoconf...

    解决办法是重新安装autoconf:

    #wget http://ftp.gnu.org/gnu/autoconf/autoconf-latest.tar.gz
    #tar -zxf autoconf-latest.tar.gz
    #rpm -qf /usr/bin/autoconf #查看autoconf的版本
    #rpm -e --nodeps autoconf-2.59-12 #卸载原来版本
    #./configure --prefix=/usr
    #make && make install

    编译安装成功后,需要在php.ini里装载模块,一般在centos里php的模块装载在/etc/php.d里面,新建一个文件aop.ini ,内容为:

    extension=aop.so

     安装成功后查看phpinfo,会看到一下内容:

    在实践之前我们需要先学习哈aop的一些专业术语。

    Aspect(切面):横向切面关系被成组的放进一个类中。
    Advice(通知):用于调用切面,定义某种情况下做什么和什么时间做这件事情。通知又分为:前通知、返回后通知、抛出后通知和周边通知。
    Joinpoint(接入点):创建通知的位置。
    Pointcut(点切割):定义了一种把通知匹配到某些接入点的方式。
     

    了解了这些知识之后我们还需要下载aop-php的说明文档。官方文档下载 
     

    在实践之前我们需要准备四个文件:测试函数文件testfunction.php、测试类文件testclass.php、测试aop文件testaop.php和运行文件test.php。

    这样做可以真实模拟我们的项目,大部分的项目都是这样布局的。

    testfunction.php代码:

    function testFunc1(){
        echo 'aop_add_before <br/>';
    }

    testaop.php代码:

    $testpoint1 = function () {
      echo "这是前切点测试函数:";
    };
    aop_add_before('testFunc1()', $testpoint1);

     test.php代码:

    require 'testaop.php';
    require 'testclass.php';
    require 'testfunction.php';
    header("Content-Type:text/html;charset=utf-8"); 
    testFunc1();

    不出意外,执行test.php我们将会看到:

    这是前切点测试函数:aop_add_before 

    testclass.php代码:

    class testClass1
    {
        public function testBeforAdd1()
        {
            echo get_class($this);
        }
    }

    testaop.php代码:

    $testpoint1 = function () {
    echo "这是前切点测试函数:";
    };
    $testpoint2 = function () {
    echo "这是前切点测试类方法:";
    };
    aop_add_before('testFunc1()', $testpoint1);
    aop_add_before('testClass1->testBeforAdd1()', $testpoint2);

    test.php代码:

    require 'testaop.php';
    require 'testclass.php';
    require 'testfunction.php';
    header("Content-Type:text/html;charset=utf-8"); 
    testFunc1();
    $testClass1 = new testClass1();
    echo $testClass1->testBeforAdd1();

    执行test.php

    这是前切点测试函数:aop_add_before 
    这是前切点测试类方法:testClass1

    testclass.php源码

    //测试前通知类
    class testClass1
    {
        public function testBeforAdd1()
        {
            echo get_class($this) .'<br />';
        }        
    }
    //测试前通知类属性
    class testClass2
    {
        private $name;
        public $publicProperty1 = 'test';
        public function __construct ($name)
        {
            $this->name = $name;
        }
        public function getName ()
        {
            return $this->name;
        }
        public function test ()
        {
            $this->publicProperty1 = 'test';
            return $this->publicProperty1;
        }
            
    }

    testaop.php源码

    $testpoint11 = function  ()
    {
        echo "这是前切点测试函数:";
    };
    $testpoint12 = function  ()
    {
        echo "这是前切点测试类方法:";
    };
    aop_add_before('testFunc1()', $testpoint11);
    aop_add_before('testClass1->testBeforAdd1()', $testpoint12);
    //------测试类属性
    class changeProperty
    {
        public function shoot ( $who, $what)
        {
            if($what == 'test'){
                $what = '测试前通知类属性截取 <br/>';
            }
            echo "$who 想要 $what ";
        }
    }
    $testclass1 = new changeProperty();
    $testpoint2 = function  ( AopJoinPoint $aop_tjp ) use( $testclass1 )
    {
        if ( $aop_tjp->getKindOfAdvice() === AOP_KIND_BEFORE_READ_PROPERTY )
        {
            return; // 如果属性不能读则返回
        }
        elseif ( $aop_tjp->getKindOfAdvice() === AOP_KIND_BEFORE_WRITE_PROPERTY )
        {
            $testclass1->shoot($aop_tjp->getObject()->getName(),$aop_tjp->getAssignedValue());
        }
    };
    //测试类属性
    aop_add_before('testClass2->publicProperty1', $testpoint2);

    test.php源码

    require 'testaop.php';
    require 'testclass.php';
    require 'testfunction.php';
    header("Content-Type:text/html;charset=utf-8"); 
    //前通知
    testFunc1();
    $testClass1 = new testClass1();
    echo $testClass1->testBeforAdd1();
    $runtest2 = new testClass2('skyboy');
    $runtest2->test();

    执行test.php

    这是前切点测试函数:aop_add_before 
    这是前切点测试类方法:testClass1
    skyboy 想要 测试前通知类属性截取 

    返回后通知aop_add_after:

    在代码中一些特殊点之后使用的通知,一般是调用一个方法或者函数。

    testfunction.php源码:

    function testFunc2(){
        echo '这是返回后通知测试:';
    }

    testaop.php源码:

    //测试返回后通知
    $testpoint22 = function  ()
    {
        echo "aop_add_after <br/>";
    };
    aop_add_after('testFunc2()', $testpoint22);

    test.php源码:

    //后通知
    testFunc2();

    执行test.php

    这是返回后通知测试:aop_add_after
    

    类和类属性和前通知类似,为了节省篇幅,这里偷懒了。

    周边通知aop_add_around

    testfunction.php源码:

    function testFunc3($param1,$param2){
        return $param1. $param2;
    }

    testaop.php源码:

    //测试周边通知
    
    function testaround (AopJoinPoint $object)
    {
        $args = $object->getArguments();
        if ($args[0] !== null) {
            $args[0] = '我想测试';
        }
        if ($args[1] !== null) {
            $args[1] = '周边通知:';
        }
        $object->setArguments($args);
        $object->process();
        
        $returnValue = $object->getReturnedValue();
        $returnValue .= 'aop_add_around<br/>';
        $object->setReturnedValue($returnValue);
        
    }
    aop_add_around('testFunc3()', 'testaround');

    test.php源码:

    //周边通知
    echo testFunc3(1,2);

    执行test.php

    我想测试周边通知:aop_add_around

    常用函数

    除了三个重要函数aop_add_before,aop_add_after,aop_add_around之外,我们还要记住这几个重要的函数。

    getKindOfAdvice

    getArguments :获取方法的参数。一般用在aop_add_before/aop_add_around。

    setArguments :设置方法的参数。一般用在aop_add_before/aop_add_around。

    getReturnedValue :获取方法的返回值。一般用在aop_add_after/aop_add_around。

    setReturnedValue:设置方法的返回值。一般用在aop_add_after/aop_add_around。

    process:让方法运行。一般用在aop_add_around。

    AOP_PHP开启和关闭

    新建一个文件aopopenclose.php

    ini_set("aop.enable", "1");
    echo "aop is enabled<br />";
    function foo ()
    {
        echo "I'm foo<br />";
    }
    $adviceShowFoo = function  ()
    {
        echo "After foo<br />";
    };
    aop_add_after('foo()', $adviceShowFoo);
    foo();
    ini_set('aop.enable', '0');
    echo "aop is now disabled<br />";
    foo();
    echo "But you can still register new aspects<br />";
    aop_add_after('f*()', $adviceShowFoo);
    foo();
    ini_set('aop.enable', '1');
    echo "Aop is now enabled<br />";
    foo();

    运行结果:

    aop is enabled
    I'm foo
    After foo
    aop is now disabled
    I'm foo
    After foo
    But you can still register new aspects
    I'm foo
    After foo
    After foo
    Aop is now enabled
    I'm foo
    After foo
    After foo

    初涉PHP-AOP的我受教了

    站在大佬的肩膀上你会看的更远,此文转载:https://www.cnblogs.com/xpbb/p/3282829.html

     
  • 相关阅读:
    二叉树的建立和遍历
    canvas基础入门(一)canvas的width、height于css样式中的宽高区别
    js实现放大镜效果
    ios中页面底部输入框,position:fixed元素的问题
    js input复选框选中父级同时子级也选中
    js apply和call
    javascript闭包理解
    vue.js vue-jsonp解决跨域问题
    vue.js请求数据(axios)
    vuex
  • 原文地址:https://www.cnblogs.com/Essaycode/p/10165375.html
Copyright © 2011-2022 走看看