PHP中静态成员的继承

时间:2009-02-10 15:19:52

标签: php inheritance

在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 :(

3 个答案:

答案 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();