php之aop实践

aop简介

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

aop-php简介

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

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

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

网址:http://aop-php.github.io/

aop-php安装

安装

有两种安装模式:

第一种方法:

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-php学前准备

专业术语

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

Aspect(切面):横向切面关系被成组的放进一个类中。

Advice(通知):用于调用切面,定义某种情况下做什么和什么时间做这件事情。通知又分为:前通知、返回后通知、抛出后通知和周边通知。

Joinpoint(接入点):创建通知的位置。

Pointcut(点切割):定义了一种把通知匹配到某些接入点的方式。

具体可以参考这篇博客:http://www.cnblogs.com/baochuan/archive/2012/08/22/2644529.html

参考文档

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

好了,E文好的可以看官方文档,直接飘过下面的文字。

准备文件

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

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

aop-php实践之通知

前通知aop_add_before

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

我们先测试函数

testfunction.php代码:

<?php
function testFunc1(){
    echo ‘aop_add_before <br/>‘;
}

testaop.php代码:

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

test.php代码:

<?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代码:

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

testaop.php代码:

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

test.php代码:

<?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源码

<?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源码

<?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源码

<?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-php函数说明

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

getKindOfAdvice

获取通知的类型。有以下几个默认值。一般用在方法的属性更改。

• AOP_KIND_BEFORE before a given call, may it be function, method or property
• AOP_KIND_BEFORE_METHOD before a method call (method of an object)
• AOP_KIND_BEFORE_FUNCTION before a function call (not a method call)
• AOP_KIND_BEFORE_PROPERTY before a property (read or write)
• AOP_KIND_BEFORE_READ_PROPERTY before a property access (read only)
• AOP_KIND_BEFORE_WRITE_PROPERTY before a property write (write only)
• AOP_KIND_AROUND around a given call, may it be function, method or property access (read / write)
• AOP_KIND_AROUND_METHOD around a method call (method of an object)
• AOP_KIND_AROUND_FUNCTION around a function call (not a method call)
• AOP_KIND_AROUND_PROPERTY around a property (read or write)
• AOP_KIND_AROUND_READ_PROPERTY around a property access (read only)
• AOP_KIND_AROUND_WRITE_PROPERTY around a property write (write only)
• AOP_KIND_AFTER after a given call, may it be function, method or property access (read / write)
• AOP_KIND_AFTER_METHOD after a method call (method of an object)
• AOP_KIND_AFTER_FUNCTION after a function call (not a method call)
• AOP_KIND_AFTER_PROPERTY after a property (read or write)
• AOP_KIND_AFTER_READ_PROPERTY after a property access (read only)
• AOP_KIND_AFTER_WRITE_PROPERTY after a property write (write only)

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

源码如下:

<?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

  

aop-php总结

aop-php在真实意义上实现了php的aop,用户无需用其他的方式即可轻松实现。aop的编程思想是一把利刃,可以让耦合性差的项目轻松实现解耦。

全部测试文件和编辑后文件打包。点此下载。(基于ceotos环境php5.3编译)

链接

时间: 2024-10-15 01:23:19

php之aop实践的相关文章

Spring入门之AOP实践:@Aspect + @Pointcut + @Before / @Around / @After

零.准备知识 1)AOP相关概念:Aspect.Advice.Join point.Pointcut.Weaving.Target等. ref: https://www.cnblogs.com/zhangzongle/p/5944906.html  有代码示例 2)相关注解:@Aspect.@Pointcut.@Before.@Around.@After.@AfterReturning.@AfterThrowing 一.实践目标 1)@Aspect的功能 2)@Pointcut的切面表达式 3)

Method Swizzling 和 AOP 实践(转)

上一篇介绍了 Objective-C Messaging.利用 Objective-C 的 Runtime 特性,我们可以给语言做扩展,帮助解决项目开发中的一些设计和技术问题.这一篇,我们来探索一些利用 Objective-C Runtime 的黑色技巧.这些技巧中最具争议的或许就是 Method Swizzling . 介绍一个技巧,最好的方式就是提出具体的需求,然后用它跟其他的解决方法做比较. 所以,先来看看我们的需求:对 App 的用户行为进行追踪和分析.简单说,就是当用户看到某个 Vie

AOP技术应用和研究--AOP简单应用

为了更好的理解AOP实践和体现AOP的优势,我们始终将OOP和AOP的比较贯穿到下文中.并在最终总结出AOP与OOP相比所拥有的优点,AOP的缺点以及AOP一般的使用场景. 1.1 问题空间到解空间的映射 在比较研究OOP和AOP实践之前,先让解决从理论上OOP和AOP解决问题的差别,也就是它们各自从问题空间到解空间的不同映射关系. 1.1.1"问题空间"和"解空间"的定义 在不同的文献中对其定义有着细微的差别,本文对其定义的如下:        问题空间(prob

AOP面向方面(切面)编程

1.引言 软件开发的目标是要对世界的部分元素或者信息流建立模型,实现软件系统的工程需要将系统分解成可以创建和管理的模块.于是出现了以系统模块化特性的面向对象程序设计技术.模块化的面向对象编程极度极地提高了软件系统的可读性.复用性和可扩展性.向对象方法的焦点在于选择对象作为模块的主要单元,并将对象与系统的所有行为联系起来.对象成为问题领域和计算过程的主要元素.但面向对象技术并没有从本质上解决软件系统的可复用性.创建软件系统时,现实问题中存在着许多横切关注点,比如安全性检查.日志记录.性能监控,异常

Spring学习笔记三(AOP中的那些事)

1.前言 前两篇博客介绍了一下,Spring中的IOC容器,这篇来讲解一下Spring中的AOP的知识.  2.AOP基础知识 2.1 概念 AOP是一种面向切面编程,一种软件工程的编程范式.AOP关注的是程序中的共性的功能,开发时,将共性功能抽取出来制作成独立的模块,此时原始代码中将不再具有这些被抽取出来的共性功能代码.因此加强了代码的复用性,同时程序开发时可以只考虑个性化功能,不需要考虑共性的功能. 2.2 基本知识点 连接点:具有特定功能的方法,一般方法 切入点:具有共性功能的方法的统称的

也说AOP

前言 1.引言 2.Aop概念 3.Aop实践 4.总结 一.引言 对于初入行的小白来讲,aop,ioc这两个程序设计思想总是傻傻分不清,不知道是个什么东东?别人再一谈各种框架更是云里雾里...博主今天带大家且先入个门,哈哈:) 二.Aop概念 AOP为Aspect Oriented Programming的缩写,译为:面向切面编程.通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. 三.Aop实践 在开发中,相信大家都遇到过验证用户权限的事情,那是不是需要在每个界面上都要加个判断

【转】.net MVC 生命周期

对于Asp.net MVC,我对它的生命周期还是兴趣很浓,于是提出两个问题: 一个HTTP请求从IIS移交到Asp.net运行时,Asp.net MVC是在什么时机获得了控制权并对请求进行处理呢?处理过程又是怎样的? 以IIS7中asp.net应用程序生命周期为例,下图是来自MSDN的一张HTTP请求处理过程发生事件的简图,后面我列出了一个完整的事件列表.既然Asp.net Mvc还是以Asp.net运行时为基础那么它必然要在Asp.net应用程序的生命周期中对请求进行截获.第一反应当然是去we

iOS开发——语法篇OC篇&amp;高级语法精讲二

Objective高级语法精讲二 Objective-C是基于C语言加入了面向对象特性和消息转发机制的动态语言,这意味着它不仅需要一个编译器,还需要Runtime系统来动态创建类和对象,进行消息发送和转发.下面通过分析Apple开源的Runtime代码(我使用的版本是objc4-646.tar)来深入理解Objective-C的Runtime机制. Runtime数据结构 在Objective-C中,使用[receiver message]语法并不会马上执行receiver对象的message方

MVC学习笔记---MVC生命周期

Asp.net应用程序管道处理用户请求时特别强调"时机",对Asp.net生命周期的了解多少直接影响我们写页面和控件的效率.因此在2007年和2008年我在这个话题上各写了一篇文章: <日志不说谎--Asp.net的生命周期> <日志不说谎--Asp.net的生命周期 [结题]> <两个粒度看Asp.net生命周期> 对于Asp.net MVC,我对它的生命周期还是兴趣很浓,于是提出两个问题: 一个HTTP请求从IIS移交到Asp.net运行时,As