Наследование статических членов в 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 :(
Ответы
Ответ 1
Классический пример того, почему использование статистики как глобальных (функции в этом случае) - плохая идея независимо от языка.
Самый надежный метод - создать несколько подэлементов реализации абстрактного базового класса Action.
Затем, чтобы попытаться удалить часть раздражения экземпляра экземпляра класса, чтобы вызвать его методы, вы можете его обернуть в factory.
Например:
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";
}
}
Затем создайте factory для "помощи" при создании функции
class ActionFactory {
public static function get($action_name) {
//... return AbstractAction instance here
}
}
Затем используйте его как:
ActionFactory::get('foo')->do();
Ответ 2
Предстоящая версия 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;
}
}
Ответ 3
На самом деле, я думаю, что это не так: вы можете ovverride статические propeties ( вам >= 5.3 PHP для этого). Но вы должны быть осторожны при переопределении этого статического свойства (и это ошибка в исходном коде)
Вам нужно использовать static:: $myStaticProperty вместо использования self:: $myStaticProperty
self:: будет ссылаться на текущий класс, поэтому, если вы находитесь внутри унаследованного статического метода, это будет refrence статическое свойство этого класса, определяющего этот метод! При использовании ссылочного ключевого слова static:: будет действовать как $this - когда вы используете методы экземпляра /propeties.
doSomething() - унаследованный статический метод в классе Bar в вашем примере. Поскольку вы использовали self:: there, он ссылается на статическое свойство класса Foo. Вот почему вы не заметили разницы... Попробуйте изменить self:: to 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:
class A var - override
класс A var2 - значение переписать
значение из класса A
- теперь тестирование класса B:
класс B var - override
класс A var2 - значение переписать
теперь вызывая B:: modStaticProperty()...
класс B - измененное значение! - переписать значение
- теперь повторное тестирование класса A:
class A var - override
класс B - измененное значение! - переопределить значение
значение из класса A
И вот мы здесь, вы можете увидеть разницу между переопределенными и только перезаписанными статическими свойствами... посмотрите строку вывода, выделенную полужирным шрифтом! Когда мы вызывали modStaticProperty() класса B, он также менял значение этой статической переменной в классе A. Поскольку это статическое свойство было унаследовано и не было переоценено! Подумайте об этом...