Наследование статических элементов в PHP


В 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 :(
Author: hakre, 2009-02-10

3 answers

Классический пример того, почему использование статики в качестве глобальных (в данном случае функций) - плохая идея, независимо от языка.

Наиболее надежным методом является создание нескольких подклассов реализации абстрактного базового класса "Действие".

Затем, чтобы попытаться устранить некоторые неудобства, связанные с созданием экземпляра класса только для вызова его методов, вы можете обернуть его в какую-нибудь фабрику.

Например:

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();
 15
Author: Allain Lalonde, 2009-02-10 15:30:19

На самом деле я думаю, что это неправда: вы можете изменить статические свойства ( для этого вам нужно >=5.3 PHP). Но вы должны быть осторожны при повторном использовании этого статического свойства (и это ошибка в исходном коде)

Вам нужно использовать статический::$mystaticproperty вместо использования self::$mystaticproperty

self:: будет ссылаться на текущий класс, поэтому, если вы находитесь внутри унаследованного статического метода, это будет ссылаться на статическое свойство этого класса определил этот метод! При использовании ссылочного ключевого слова static:: будет действовать как $this - когда вы используете методы/свойства экземпляра.

doSomething() - это унаследованный статический метод в панели классов в вашем примере. Поскольку вы использовали self::там, он будет ссылаться на статическое свойство класса Foo. Вот почему вы не увидели никакой разницы... Попробуйте изменить себя:: на статический::!

Вот пример кода - я сам использовал его для тестирования этих вещей. У нас есть статическое наследование свойств/методов, переопределение и изменение значений в нем - запустите его, и вы увидите результат!

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 var - переопределение
класс A var2 - перезапись значения
значение из класса A
-- теперь тестируем класс B:
класс B var - переопределение
класс A var2 - перезапись значения
теперь вызываем B::modstaticproperty()...
класс В - измененное значение! - перезапись значения
-- теперь повторное тестирование класса А:
класс А var - переопределение
класс В - измененное значение! - перезапись значения
значение из класса А

И вот мы здесь, вы можете увидеть разницу между переопределенными и только перезаписанными статическими свойствами... посмотрите на выходную строку, которую я выделил жирным шрифтом! Когда мы вызвали функцию modStaticProperty() класса B, она также изменила значение этой статической переменной в классе A. Поскольку это статическое свойство было унаследовано и не было переопределено! Подумайте об этом...

 29
Author: Attila Wind, 2013-02-17 09:58:30

Предстоящий выпуск PHP 5.3.0 включает позднюю статическую привязку, которая может помочь. Используя эту функцию, вы можете использовать статическую переменную внутри статического метода и позволить поздней статической привязке позаботиться о поиске "правильного" метода.

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;
    }
}
 27
Author: Paul Dixon, 2009-02-10 15:35:01