在PHP中,如果在父类中定义了静态属性,则无法在子类中重写它。但我想知道是否有任何解决方法。
我正在尝试为其他人(有点笨重)的函数编写一个包装器。有问题的函数可以应用于许多不同的数据类型,但每个都需要不同的标志和选项。但99%的情况下,每种类型的默认值就足够了。
如果可以通过继承完成,而不必每次都编写新函数,那将是很好的。例如:
class Foo {
public static $default = 'DEFAULT';
public static function doSomething ($param = FALSE ) {
$param = ($param === FALSE) ? self::$default : $param;
return $param;
}
}
class Bar extends Foo {
public static $default = 'NEW DEFAULT FOR CHILD CLASS';
}
echo Foo::doSomething() . "\n";
// echoes 'DEFAULT'
echo Bar::doSomething() . "\n";
// echoes 'DEFAULT' not 'NEW DEFAULT FOR CHILD CLASS'
// because it references $default in the parent class :(
答案 0 :(得分:31)
实际上我认为事实并非如此:你可以提供静态功能(你需要> = 5.3 PHP )。但是在为那个静态属性重新注册时你必须要小心(这是原始代码中的错误)
你需要使用 static :: $ myStaticProperty 而不是使用self :: $ myStaticProperty
self :: 会引用当前类,所以如果你在一个继承的静态方法中,这将引用该方法定义的那个类的静态属性!使用引用关键字static ::会像$ this一样 - 当你使用实例方法/ propeties时
doSomething()是示例中类Bar中的继承静态方法。由于你使用self :: there,它将引用类Foo的static属性。这就是你没有看到任何区别的原因...... 尝试将self ::改为static :: !
这是一个代码示例 - 我自己用它来测试这些东西。我们有静态属性/方法继承,覆盖和值更改 - 运行它,你会看到结果!
class A {
// a static property - we will test override with it
protected static $var = 'class A var - override';
// a static property - we will test value overwrite with it
protected static $var2 = 'class A var2 - value overwrite';
public static function myStaticOverridePropertyTest() {
return static::$var;
}
public static function myStaticValueOverwritePropertyTest() {
return static::$var2;
}
/**
* This method is defined only here - class B will inherit this one!
* We use it to test the difference btw self:: and static::
*
* @return string
*/
public static function myStaticMethodTest() {
//return self::getValue();
return static::getValue();
}
/**
* This method will be overwritten in class B
* @return string
*/
protected static function getValue() {
return 'value from class A';
}
}
class B extends A {
// we override this inherited static property
protected static $var = 'class B var - override';
/**
* This method is overwritten from class A
* @return string
*/
protected static function getValue() {
return 'value from class B';
}
/**
* We modify the value of the inherited $var2 static property
*/
public static function modStaticProperty() {
self::$var2 = 'class B - altered value! - value overwrite';
}
}
echo ("-- testing class A:\n");
echo (A::myStaticOverridePropertyTest(). "\n");
echo (A::myStaticValueOverwritePropertyTest(). "\n");
echo (A::myStaticMethodTest(). "\n");
echo ("-- now testing class B:\n");
echo (B::myStaticOverridePropertyTest(). "\n");
echo (B::myStaticValueOverwritePropertyTest(). "\n");
echo (" now invoking B::modStaticProperty() .\n");
B::modStaticProperty();
echo (B::myStaticValueOverwritePropertyTest(). "\n");
echo ("-- now re-testing class A:\n");
echo (A::myStaticOverridePropertyTest(). "\n");
echo (A::myStaticValueOverwritePropertyTest(). "\n");
echo (A::myStaticMethodTest(). "\n");
这将输出:
- 测试A类:
A类var - 覆盖
class A var2 - 值覆盖
A类价值
- 现在测试B类:
B级var - 覆盖
class A var2 - 值覆盖
现在调用B :: modStaticProperty()...
B级 - 改变价值! - 值覆盖
- 现在重新测试A类:
A类var - 覆盖
B级 - 改变价值! - 值覆盖
A类价值
在这里,我们可以看到覆盖和仅覆盖静态属性之间的区别...查看我用粗体标记的输出行!当我们调用类B的modStaticProperty()时,它也改变了类A中的静态变量的值。由于该静态属性是继承的并且未被覆盖!想一想......
答案 1 :(得分:27)
即将推出的PHP 5.3.0版本包括late static binding,这可能有所帮助。使用此功能,您可以在静态方法中使用静态变量,并让后期静态绑定负责查找“正确”方法。
class Foo {
public static function getDefault() {
static $default = 'DEFAULT';
return $default;
}
public static function doSomething ($param) {
$default=static::getDefault(); // here is the late static binding
$param = ($param === FALSE) ? $default : $param;
return $param;
}
}
class Bar extends Foo {
public static function getDefault() {
static $default = 'NEW DEFAULT FOR CHILD CLASS';
return $default;
}
}
答案 2 :(得分:16)
为什么使用静态作为全局变量(在这种情况下是函数)的经典示例无论语言如何都是一个坏主意。
最强大的方法是创建抽象基类“Action”类的多个实现子类。
然后尝试删除实例化类实例的一些烦恼只是为了调用它的方法,你可以将它包装在某种工厂中。
例如:
abstract class AbstractAction {
public abstract function do();
}
class FooAction extends AbstractAction {
public function do() {
echo "Do Foo Action";
}
}
class BarAction extends AbstractAction {
public function do() {
echo "Do Bar Action";
}
}
然后创建一个工厂来“帮助”实现函数
class ActionFactory {
public static function get($action_name) {
//... return AbstractAction instance here
}
}
然后将其用作:
ActionFactory::get('foo')->do();