【问题标题】:Inheritance of static members in PHPPHP中静态成员的继承
【发布时间】:2010-10-06 16:15:03
【问题描述】:

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

【问题讨论】:

    标签: php inheritance


    【解决方案1】:

    实际上我认为这不是真的:您可以覆盖静态属性(为此您需要 >=5.3 PHP)。但是在引用该静态属性时必须小心(这是原始代码中的错误)

    您需要使用 static::$myStaticProperty 而不是使用 self::$myStaticProperty

    self:: 将参考 当前类 因此,如果您在继承的静态方法中,这将引用该类的静态属性定义该方法!使用引用关键字时 static:: 会像 $this - 当您使用实例方法/属性时。

    在您的示例中,doSomething() 是类 Bar 中的继承静态方法。由于您在那里使用了 self::,它将引用类 Foo 的静态属性。这就是您没有看到任何差异的原因... 尝试将 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 - 覆盖
    A 类 var2 - 值覆盖
    A类的价值
    -- 现在测试 B 类:
    B 类 var - 覆盖
    A 类 var2 - 值覆盖
    现在调用 B::modStaticProperty() ...
    B 级 - 改变的价值! - 值覆盖
    -- 现在重新测试 A 类:
    A 类 var - 覆盖
    B 类 - 改变值! - 值覆盖
    A类的价值

    在这里,您可以看到覆盖静态属性和仅值覆盖静态属性之间的区别......看看我用粗体标记的输出行!当我们调用 B 类的 modStaticProperty() 时,它也改变了 A 类中该静态变量的值。由于该静态属性是继承的并且没有被覆盖!想一想……

    【讨论】:

    【解决方案2】:

    即将发布的 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;
        }
    }
    

    【讨论】:

    • 这将是可爱的,感谢您的信息。但是,唉,我需要一些可以在我当前的生产环境(5.2.6)中运行的东西。谢谢!
    【解决方案3】:

    为什么使用静态作为全局变量(在本例中为函数)是一个坏主意的经典示例,无论使用哪种语言。

    最健壮的方法是创建抽象基础“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();
    

    【讨论】:

      猜你喜欢
      • 2015-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-09
      • 2023-03-14
      • 1970-01-01
      • 2014-10-08
      相关资源
      最近更新 更多