php之aop實踐

aop簡介

AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程(也叫面向方面),能夠經過預編譯方式和運行期動態代理實如今不修改源代碼的狀況下給程序動態統一添加功能的一種技術。AOP實際是GoF設計模式的延續,設計模式孜孜不倦追求的是調用者和被調用者之間的解耦,AOP能夠說也是這種目標的一種實現。php

 

aop-php簡介

 

AOP-PHP是一個PECL擴展,您能夠在PHP中使用面向方面的編程,無需編譯或進行其餘任何中間步驟。html

AOP擴展的設計是最簡單的方法,你能夠認爲PHP中的aop實現。node

AOP旨在讓橫切關注點的分離(緩存,日誌,安全,交易,……)git

 

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

 

aop-php安裝

安裝

有兩種安裝模式:編程

第一種方法:centos

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(點切割):定義了一種把通知匹配到某些接入點的方式。
 
 

參考文檔

 
瞭解了這些知識以後咱們還須要下載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編譯)

相關文章
相關標籤/搜索