close
話說 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();
}
}
不過他寫插件的方法我不是很喜歡,正好我最近開始復工在寫的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();
}
}
全站熱搜
留言列表