我們使用MVC架構,例如CI、YII、cakePHP,原因之一就是:能夠使代碼便於維護。
但當商務邏輯不斷複雜時,在控制器中調用模型中的方法會越來越臃腫。
面向切面編程的思路,是解決不斷變化的商務邏輯與寫出便於維護代碼的解決方案之一。
下面是向切面式組件源碼,是根據AOP的思路設計的。
<?phpif (function_exists('__autoload')) {trigger_error("Extension: It looks like your code is using an __autoload() function. Extension uses spl_autoload_register() which will bypass your __autoload() function and may break autoloading.", E_USER_WARNING);}spl_autoload_register(array('ExtensionFactory', 'autoload'));class ExtensionFactory { private static $extFamily = null; private static $_classes = array( 'Extension' => '/Extension.php', 'ExtensionFamily' => '/ExtensionFamily.php' ); /** * Class autoloader. This method is provided to be invoked within an * __autoload() magic method. * @param string $className The name of the class to load. */ public static function autoload() { foreach(self::$_classes as $v){ require_once dirname(__FILE__) . $v; } } /** * 必須先調用此方法來執行個體化擴充族,才能調用addExtension\removeExtension等 * @return ExtensionFamily */ public static function createExtension(){ self::$extFamily = new ExtensionFamily(); return self::$extFamily; } public static function removeExtension($extName){ if(is_null(self::$extFamily)){ throw new Exception("Please createExtension first"); return false; }else{ unset(self::$extFamily->_extensionArray[$extName]); } } public static function addExtension($extName, Extension $ext){ if(is_null(self::$extFamily)){ throw new Exception("Please createExtension first"); return false; }else{ self::$extFamily->_extensionArray[$extName] = $ext; } } public static function removeAllExtension(){ if(is_null(self::$extFamily)){ throw new Exception("Please createExtension first"); return false; }else{ foreach(self::$extFamily->_extensionArray as $extName=>$ext){ unset(self::$extFamily->_extensionArray[$extName]); } } }}
<?php/** * 擴充家族 * * @author Mr.Jin */class ExtensionFamily implements Extension{ public $_extensionArray = array(); /** * * @param type $extName 副檔名 * @param Extension $ext 實現Extension的對象 */ public function addExtension($extName, Extension $ext){ $this->_extensionArray[$extName] = $ext; } public function beforeAppend(&$params){ foreach($this->_extensionArray as $ext){ $ext->beforeAppend($params); } } public function afterAppend(&$params) { foreach($this->_extensionArray as $ext){ $ext->afterAppend($params); } }}?>
<?php/** * 擴充介面 * * @author Mr.Jin */interface Extension { public function beforeAppend(&$params); public function afterAppend(&$params);}?>
以上三個檔案實現了簡單的AOP組件。
下面是Demo:
<?php/** * 自訂Extension * 使用者積分Extension * 根據使用者是否登入,決定此次消費是否記錄使用者積分 * * @author Mr.Jin */class ExampleExtension implements Extension {public $check=false; public function beforeAppend(&$isLogin) { if($isLogin){ $this->check = true; } } public function afterAppend(&$pointer) { if($this->check){ //add pointer }else{ echo '未登入使用者,積分不錄入'; return; } }}?>
demo.php
<?phprequire_once('ExtensionFactory.php');//匯入組件本身require_once('ExampleExtension.php');//匯入擴充$ext = ExtensionFactory::createExtension();ExtensionFactory::addExtension('example', new ExampleExtension());//積分錄入功能/* * 按照需求的變化,可以增加相應的Extension. * eg. * 新需求:新增會員類型,根據不同類型,進行價格優惠。 * 實現思路: * 一、建立卡號類型工廠 * 二、建立SeniorMemberExtension、PuTongMeberExtension. * 三、Factory 方法根據會員類型addExtension */$isLogin = false; //假設使用者未登入$ext->beforeAppend($isLogin);/** * 面向切面編程,最重要一點是:必須先分析出整個業務處理中,哪個才是重點。 * 這裡的重點是訂單的入庫。 * 在訂單入庫之前可能商務邏輯不斷增加,例如:登入驗證、卡上餘額驗證等 * 在訂單入庫之後:積分處理、訂單監控等 */echo "此處是主要商務邏輯:訂單入庫\r\n";$pointer = 100;$ext->afterAppend($pointer);
運行結果:
此處是主要商務邏輯:訂單入庫
未登入使用者,積分不錄入