2013年6月9日 星期日

php 5.3 以前獲取靜態子類別名稱的方法

轉貼自:http://inspire.twgg.org/programming/php/item/393-php-53-the-previous-sub-category-name-to-obtain-a-static-method.html




看了一下datastore的入門,以及開始採用MVC方式來寫php,於是想拿php為redis寫個model,可以實現一些datastore的基本功能...於是碰到這樣一個問題-.-
php裡__CLASS__這類東西是靜態綁定的,如果不再子類裡重載的話,那麼繼承父類方法所得到的依舊是父類的名稱而不是子類的名稱。比如:
class A{
function __construct(){
echo __CLASS__;
}
static function name(){
echo __CLASS__;
}
}
class B extends A{}
此時無論將B實例化還是直接調用靜態方法,echo出來的都會是A。翻qeephp裡是用子類重載的方式解決這個問題,可是這樣的話沒新搞一個子類就得把相應調用類名的方法重載一邊.....這算是php在oop上的缺陷吧,試了試python上沒這個問題。
google之。找到兩個函數get_class()和get_called_class()。get_class()用於實例調用,加入參數 ($this)可解決子類繼承調用的問題,而get_called_class()則是用於靜態方法調用,可是...這玩意兒只在php 5.3以後才有....5.3還是比較遙遠的事...還好5.2之前可以手動實現這個函數:參閱http://php.net/manual/en /function.get-called-class.php 下方有高手添加了幾種5.3之前的實現方式。這樣,即可實現印出靜態子類別的方法了。
 
if(!function_exists('get_called_class')) {  
    class class_tools  
    {  
        private static $i = 0;  
        private static $fl = null;  
        public static function get_called_class()  
        {  
            $bt = debug_backtrace();  
            //使用call_user_func或call_user_func_array函數調用類方法,處理如下  
            if (array_key_exists(3, $bt)  
            && array_key_exists('function', $bt[3])  
            && in_array($bt[3]['function'], array('call_user_func', 'call_user_func_array'))  
            ) {  
                //如果參數是數組  
                if (is_array($bt[3]['args'][0])) {  
                    $toret = $bt[3]['args'][0][0];  
                    return $toret;  
                }else if(is_string($bt[3]['args'][0])) {//如果參數是字符串  
                    //如果是字符串且字符串中包含::符號,則認為是正確的參數類型,計算並返回類名  
                    if(false !== strpos($bt[3]['args'][0], '::')) {  
                        $toret = explode('::', $bt[3]['args'][0]);  
                        return $toret[0];  
                    }  
                }  
            }  
            //使用正常途徑調用類方法,如:A::make()  
            if(self::$fl == $bt[2]['file'].$bt[2]['line']) {  
                self::$i++;  
            } else {  
                self::$i = 0;  
                self::$fl = $bt[2]['file'].$bt[2]['line'];  
            }  
            $lines = file($bt[2]['file']);  
            preg_match_all('  
            /([a-zA-Z0-9\_]+)::'.$bt[2]['function'].'/',  
            $lines[$bt[2]['line']-1],  
            $matches  
            );  
            return $matches[1][self::$i];  
        }  
    }  
    
    
    function get_called_class()  
    {  
        return class_tools::get_called_class();  
    }  
} 
 
於是現在可以把例子這麼修改:
class A{
function __construct(){
echo get_class($this);
}
static function name(){
echo get_called_class();
}
}
class B extends A{}

這樣就能讓B直接順利繼承獲取當前類名的方法了~

沒有留言:

張貼留言