此文章作者是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 B extends A{
protected static $v='B';
}
class C 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 B extends A{
protected static $v='B';
public static function getV(){
return self::$v;
}
}
class C 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 B extends A{
protected static $v='B';
public static function getV(){
return self::$v;
}
public static function setV($v){
self::$v=$v;
}
}
class C extends B {
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是否能够改变这种方式,希望如此。