В чем разница между self:: $bar и static:: $bar в PHP?

В чем разница между использованием self и static в приведенном ниже примере?

class Foo
{
    protected static $bar = 1234;

    public static function instance()
    {
        echo self::$bar;
        echo "\n";
        echo static::$bar;
    }

}

Foo::instance();

производит

1234
1234

Ответ 1

Когда вы используете self для ссылки на член класса, вы ссылаетесь на класс, в котором вы используете ключевое слово. В этом случае ваш класс Foo определяет защищенное статическое свойство, называемое $bar. Когда вы используете self в классе Foo для ссылки на свойство, вы ссылаетесь на тот же класс.

Поэтому, если вы попытались использовать self::$bar в другом месте вашего класса Foo, но у вас был класс Bar с другим значением для свойства, он использовал бы Foo::$bar вместо Bar::$bar, что может не быть тем, что вы намерены:

class Foo
{
    protected static $bar = 1234;
}

class Bar extends Foo
{
    protected static $bar = 4321;
}

Когда вы используете static, вы вызываете функцию поздние статические привязки (введены в PHP 5.3).

В приведенном выше сценарии использование static вместо self приведет к использованию Bar::$bar вместо Foo::$bar, потому что тогда интерпретатор учитывает повторную декларацию в классе Bar.

Обычно используются поздние статические привязки для методов или даже самого класса, а не свойства, поскольку вы не часто переопределяете свойства в подклассах; пример использования ключевого слова static для вызова конструктора с поздними ограничениями можно найти в этом связанном вопросе: Новое я против нового статического

Однако это не исключает использования static со свойствами.

Ответ 2

self - refers to the same class whose method the new operation takes place in.

static - in PHP 5.3 late static binding refers to whatever class in the hierarchy which you call the method on.

В следующем примере (см. Get_called_class()) класс B наследует оба метода от класса A. Self связан с A, потому что он определен в реализации метода A, тогда как static связан с вызываемым классом, несмотря на то, что он также в Реализация метода.

class A {
    public static function get_A() {
        return new self();
    }

    public static function get_me() {
        return new static();
    }
}

class B extends A {}

echo get_class(B::get_A());  // A
echo get_class(B::get_me()); // B
echo get_class(A::get_me()); // A