Подтвердить что ты не робот

Наследование статических членов в 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 :(
4b9b3361

Ответ 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. Поскольку это статическое свойство было унаследовано и не было переоценено! Подумайте об этом...