php5-static的問題

此文章作者是nightsailer

這幾天在將我的doggy框架移植到PHP5的時候發現了一些小問題,主要是PHP5的static的實現上和其他的OO語言有很大的不同。
先看一部分代碼

複製PHP內容到剪貼板
PHP代碼:
class A{
    protected static 
$v='A';
    public static function 
getV(){
         return 
self::$v;
    }
    public static function 
setV($v){
         
self::$v=$v;
    }
}
class 
extends A{
    protected static 
$v='B';
}
class 
extends B{
    protected static 
$v='C';
}
echo 
'A::getV '.A::getV();
echo 
'B::getV '.B::getV();
echo 
'C::getV '.C::getV();

按通常的理解,應該是:

A::getV A
B::getV B
C::getV C

但輸出的結果是:

A::getV A
B::getV A
C::getV A

再做個實驗:
複製PHP內容到剪貼板
PHP代碼:
class A{
    protected static 
$v='A';
    public static function 
getV(){
         return 
self::$v;
    }
    public static function 
setV($v){
         
self::$v=$v;
    }
}
class 
extends A{
    protected static 
$v='B';
    public static function 
getV(){
         return 
self::$v;
    }
}
class 
extends B{
    protected static 
$v='C';
}
echo 
'A::getV '.A::getV();
echo 
'B::getV '.B::getV();
echo 
'C::getV '.C::getV();

猜猜結果是什麼?

A::getV A
B::getV B
C::getV B

最後一個例子:
複製PHP內容到剪貼板
PHP代碼:
class A{
    protected static 
$v='A';
    public static function 
getV(){
         return 
self::$v;
    }
    public static function 
setV($v){
         
self::$v=$v;
    }
}
class 
extends A{
    protected static 
$v='B';
    public static function 
getV(){
         return 
self::$v;
    }
    public static function 
setV($v){
         
self::$v=$v;
    }
}
class 
extends {
    protected static 
$v='C';
}
A::setV('C');
B::setV('D');
C::setV('E');

echo 
'A::getV '.A::getV();
echo 
'B::getV '.B::getV();
echo 
'C::getV '.C::getV();

輸出結果:
A::getV C
B::getV E
C::getV E

ok

看到這裏大家都應該清楚了,PHP5的static的實現比較“特別”,從手冊裏面也能看到說明。
調用static方法是編譯時確定的,而不是按照調用時的繼承關係來確定。
簡單的說,當調用static方法時,其起始的範圍是實現這個static方法(包括重載)的類範圍,
而不是按照調用的繼承關係的類。比如調B::getV(),如果B類中定義或者重載了getV,那麼
此時確定的當前類就是B,否則向上追溯到其父類假設是A,如果A扔沒有,繼續向上查找,
一旦找到,那麼當前類就是這個定義getV的類。此時self指向的就是這個確定的類,而不是
起始調用getMethod的那個class,因此,如果此時這個類假設爲A沒有定義static $v,則會引發一個錯誤。

PHP5的這種方式導致了很多困惑,尤其希望實現static重載的時候,你無法通過在父類定義通用
的方法,而試圖通過子類重載一些static field來實現static級別的繼承。

我在用PHP5實現Active Record模式的時候遇到了這些問題,最後只能通過一些hack的手法來實現。
不知道PHP6是否能夠改變這種方式,希望如此。
發佈了31 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章