PHP的面向方面编程
|
面向方面编程(AOP)对于PHP来说是一个新的概念。现在PHP对于 AOP 并没有官方支持,但有很多扩展和库实现了这个特性。本课中,我们将使用 Go! PHP library 来学习 PHP 如何进行 AOP 开发,或者在需要的时候,可以回来看一眼。 AOP简史
面向方面编程的思想在二十世纪90年代中期,于施乐帕洛阿尔托研究中心(PARC)成型。同很多有趣的新技术一样,由于缺少明确的定义,起初 AOP 备受争议。因此相关小组决定将未完成的想法公之于众,以便接受广大社区的反馈。关键问题在于“关注点分离(Separation of Concerns)”的概念。AOP 是一种可以分离关注的可行系方案。 AOP 于90年代末趋于成熟,标识为施乐 AspectJ 的发布,IBM 紧随其后,于2001年发布了 Hyper/J。现在,AOP是一种对于常用编程语言来说都是一种成熟的技术。 基本词汇AOP 的核心就是“方面”,但在我们定义「方面『aspect』」之前,我们需要先讨论两个术语;「切点 『 point-cut』 」和「通知『advise』」。切点代表我们代码中的一个时间点,特指运行我们代码的某个时间。在切点运行代码被称为通知,结合一个活多个切点及通知的即为方面。 通常,每个类都会有一个核心的行为或关注点,但有时,类可能存在次要的行为。例如,类可能会调用一个日志记录器或是通知一个观察员。因为类中的这些功能是次要的,其行为通常都是相同的。这种行为被称为“交叉关注点”;使用 AOP 可以避免。 PHP的各种AOP工具Chris Peters 已经讨论过在PHP中实现 AOP 的Flow 框架。 Lithium 框架也提供了对AOP的实现。 另一个框架采用了不同的方法,创建了一个 C/C++ 编写的PHP扩展,在PHP解释器的层级上宣示着它的魔力。名为AOP PHP Extension,我会在后续文章中讨论它。 但正如我之前所言,本文将检阅Go! AOP-PHP 库。 安装并配置 Go!Go! 库并未扩展;它完全由PHP编写,并为PHP5.4或更高版本使用。作为一个纯PHP库,它部署简易,即使是在不允许编译安装你自己的PHP扩展的受限及共享主机环境,也可以轻易安装。 使用 Composer 安装 Go!Composer 是安装 PHP 包的首选方法。如果你没有使用过 Composer,你可以在Go! GitHub repository下载。 首先,将下面几行加入你的 composer.json 文件。
{
"require": {
"lisachenko/go-aop-php": "*"
}
}
之后,使用 Composer 安装 go-aop-php。在终端中运行下面命令: $ cd /your/project/folder $ php composer.phar update lisachenko/go-aop-php Composer 将会在之后数秒中内安装引用的包以及需求。如果成功,你将看到类似下面的输出:
Loading composer repositories with package information
Updating dependencies
- Installing doctrine/common (2.3.0)
Downloading: 100%
- Installing andrewsville/php-token-reflection (1.3.1)
Downloading: 100%
- Installing lisachenko/go-aop-php (0.1.1)
Downloading: 100%
Writing lock file
Generating autoload files
在安装完成后,你可以在你的代码目录中发现名为 vendor 的文件夹。Go! 库及其需求就安装在这。 $ ls -l ./vendor total 20 drwxr-xr-x 3 csaba csaba 4096 Feb 2 12:16 andrewsville -rw-r--r-- 1 csaba csaba 182 Feb 2 12:18 autoload.php drwxr-xr-x 2 csaba csaba 4096 Feb 2 12:16 composer drwxr-xr-x 3 csaba csaba 4096 Feb 2 12:16 doctrine drwxr-xr-x 3 csaba csaba 4096 Feb 2 12:16 lisachenko $ ls -l ./vendor/lisachenko/ total 4 drwxr-xr-x 5 csaba csaba 4096 Feb 2 12:16 go-aop-php 整合到我们的项目我们需要创建一个调用,介于路由/应用程序的入口点。自动装弹机的然后自动包括类。开始吧!引用作为一个切面内核。
use GoCoreAspectKernel;
use GoCoreAspectContainer;
class ApplicationAspectKernel extends AspectKernel {
protected function configureAop(AspectContainer $container) {
}
protected function getApplicationLoaderPath() {
}
}
现在,AOP是一种在通用编程语言中相当成熟的技术。 例如,我创建了一个目录,调用应用程序,然后添加一个类文件: ApplicationAspectKernel.php 。 我们开始切面扩展!AcpectKernel 类提供了基础的方法用于完切面内核的工作。有两个方法,我们必须知道:configureAop()用于注册页面特征,和 getApplicationLoaderPath() 返回自动加载程序的全路径。 现在,一个简单的建立一个空的 autoload.php 文件在你的程序目录。和改变 getApplicationLoaderPath() 方法。如下:
// [...]
class ApplicationAspectKernel extends AspectKernel {
// [...]
protected function getApplicationLoaderPath() {
return __DIR__ . DIRECTORY_SEPARATOR . 'autoload.php';
}
}
别担心 autoload.php 就是这样。我们将会填写被省略的片段。 当我们第一次安装 Go语言!和达到这一点我的过程中,我觉得需要运行一些代码。所以开始构建一个小应用程序。 创建一个简单的日志记录器我们的「方面」为一个简单的日志记录器,但在继续我们应用的主要部分之前,有些代码需要看一下。 创建一个最小的应用我们的小应用是一个电子经纪人,能够购买和出售股票。
class Broker {
private $name;
private $id;
function __construct($name,$id) {
$this->name = $name;
$this->id = $id;
}
function buy($symbol,$volume,$price) {
return $volume * $price;
}
function sell($symbol,$price) {
return $volume * $price;
}
}
这些代码非常简单,Broker 类拥有两个私有字段,储存经纪人的名称和 ID。 这个类同时提供了两个方法,buy() 和 sell(),分别用于收购和出售股票。每个方法接受三个参数:股票标识、股票数量、每股价格。sell() 方法出售股票,并计算总收益。相应的,buy()方法购买股票并计算总支出。 考验我们的经纪人通过PHPUnit 测试程序,我们可以很容易的考验我们经纪人。在应用目录内创建一个子目录,名为 Test,并在其中添加 BrokerTest.php 文件。并添加下面的代码:
require_once '../Broker.php';
class BrokerTest extends PHPUnit_Framework_TestCase {
function testBrokerCanBuyShares() {
$broker = new Broker('John','1');
$this->assertEquals(500,$broker->buy('GOOGL',100,5));
}
function testBrokerCanSellShares() {
$broker = new Broker('John',$broker->sell('YAHOO',50,10));
}
}
这个检验程序检查经纪人方法的返回值。我们可以运行这个检查程序检验我们的代码,至少是不是语法正确。 添加一个自动加载器让我们创建一个自动加载器,在应用需要的时候加载类。这是一个简单的加载器,基于PSR-0 autoloader.
ini_set('display_errors',true);
spl_autoload_register(function($originalClassName) {
$className = ltrim($originalClassName,'');
$fileName = '';
$namespace = '';
if ($lastNsPos = strripos($className,'')) {
$namespace = substr($className,$lastNsPos);
$className = substr($className,$lastNsPos + 1);
$fileName = str_replace('',DIRECTORY_SEPARATOR,$namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_',$className) . '.php';
$resolvedFileName = stream_resolve_include_path($fileName);
if ($resolvedFileName) {
require_once $resolvedFileName;
}
return (bool) $resolvedFileName;
});
这就是我们 autoload.php 文件中的全部内容。现在,变更 BrokerTest.php, 改引用Broker.php 为引用自动加载器 。
require_once '../autoload.php';
class BrokerTest extends PHPUnit_Framework_TestCase {
// [...]
}
运行 BrokerTest,验证代码运行情况。 连接到应用方面核心我们最后的一件事是配置Go!.为此,我们需要连接所有的组件让们能和谐工作。首先,创建一个php文件AspectKernelLoader.php,其代码如下:
include __DIR__ . '/../vendor/lisachenko/go-aop-php/src/Go/Core/AspectKernel.php';
include 'ApplicationAspectKernel.php';
ApplicationAspectKernel::getInstance()->init(array(
'autoload' => array(
'Go' => realpath(__DIR__ . '/../vendor/lisachenko/go-aop-php/src/'),'TokenReflection' => realpath(__DIR__ . '/../vendor/andrewsville/php-token-reflection/'),'DoctrineCommon' => realpath(__DIR__ . '/../vendor/doctrine/common/lib/')
),'appDir' => __DIR__ . '/../Application','cacheDir' => null,'includePaths' => array(),'debug' => true
));
这个文件位于前端控制器和自动加载器之间。他使用AOP框架初始化并在需要时调用autoload.php 第一行,我明确地载入AspectKernel.php和ApplicationAspectKernel.php,因为,要记住,在这个点我们还没有自动加载器。 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
