php5-static的问题

来源:互联网 发布:淘宝需要交保证金吗 编辑:程序博客网 时间:2024/06/06 14:00

此文章作者是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是否能够改变这种方式,希望如此。