話說 adodb lite 這套資料庫用的類別庫已經很久沒更新了,這套小巧的類別庫有一個很棒的功能,就是可以寫插件。
不過他寫插件的方法我不是很喜歡,正好我最近開始復工在寫的DB Layer也碰到這樣的難題:我想把功能分割出來,寫成可以共同合作的插件,需要什麼功能可以隨時加進去。
另外還有一點,我希望使用插件的方法時,其調用的方式等同於使用繼承的方式。

因此,我利用了PHP5的反映的功能,寫了一個插件用的抽象類別,只要繼承它,就可以簡單的寫出插件以及加入插件的功能。
底下是程式碼:



abstract class _插件{
    private $_插件 = array();
    private $_方法 = array();

    function __construct(&$插件 = null){
        $this->__插件($插件);
    }

    final function &__call($方法, $參數){
        $輸出 = call_user_func_array($this->_方法[$方法], $參數);
        return $輸出;    
    }

//    將插件的方法加入$this的方法中
    final protected function __插件(&$插件, $更新 = false){
        static $類別 = __CLASS__;
        if (false == ($插件 instanceof $類別)) {
            return false;
        }

        $名稱 = get_class($插件);
        if (false == array_key_exists($名稱, $this->_插件)){
            $this->_插件[$名稱] = $插件;
            $this->_方法 = $插件->__方法() + $this->_方法;
        }
        if ($更新) {
            $this->__更新();
        }
        return true;
    }

//    取得插件的方法(除了方法名稱開頭是'__'的方法,例如一些魔術方法,或是方法本身屬於私有方法)
    final protected function &__方法(){
        static $_方法 = array();
        if (false == empty($_方法)) {
            return $_方法;
        }
        $反映 = new ReflectionObject($this);
        $方法 = $反映->getMethods();
        unset($反映);
        foreach ($方法 as &$項目){
            $名稱 = &$項目->getName();
            if (0 !== strpos($名稱, '__') && false == $項目->isPrivate()) {
                $_方法[$名稱] = array($this, $名稱);
            }
        }
        return $_方法; 
    }
   
//    更新所有插件的方法,通常在載入所有插件後調用
    final protected function __更新(){
        static $類別 = __CLASS__;
        foreach ($this->_插件 as &$插件){
            if($插件 instanceof $類別) {
                $插件->_方法 = $this->_方法 + $插件->_方法;
            }
        }
    }   
}



這裡有個簡單的範例。
plugin.php => 插件的抽象類別檔案 (內容就是上述的抽象類別)
test01.php => 主要的範例檔案
test02.php => 插件的檔案

test01.php:

require_once dirname(__FILE__) . '/plugin.php';
class 測試 extends _插件 {
    function 載入插件($插件) {
        require_once dirname(__FILE__) . "/$插件.php";
        $類別 = __CLASS__ . ":$插件";
        $插件 = new $類別($this);
        $this->__插件($插件);
    }
   
    protected function 測試01(){
        echo __METHOD__ , '<br>';
    }
}

$測試 = new 測試();
$測試->載入插件('test02');
$測試->測試02();


test02.php:

require_once dirname(__FILE__) . '/test01.php';
class 測試:test02 extends _插件 {
    function 測試02(){
        echo __METHOD__ , '<br>';
        $this->測試01();
    }
}


arrow
arrow
    全站熱搜

    HACGIS 發表在 痞客邦 留言(1) 人氣()