Яка різниця між self :: $ bar та static :: $ bar у PHP?


125

Яка різниця між використанням selfта staticнаведеним нижче прикладом?

class Foo
{
    protected static $bar = 1234;

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

}

Foo::instance();

виробляє

1234
1234

2
@deceze: Це подібне питання, але це не дублікат. Цей запитує про використання ключових слів із властивостями, а запитує про використання їх із конструкторами.
BoltClock

Відповіді:


191

Якщо ви 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).

У вищенаведеному сценарії використання selfпризведе до Foo::$bar(1234). І використання staticпризведе до Bar::$bar(4321), оскільки static, інтерпретатор бере до уваги передекларацію в Barкласі під час виконання.

Зазвичай ви використовуєте пізні статичні прив’язки для методів або навіть самого класу, а не властивостей, оскільки ви часто не переосмислюєте властивості в підкласах; Приклад використання staticключового слова для виклику конструктора із запізненням можна знайти у цьому пов'язаному питанні: Новий власний та новий статичний

Однак це також не виключає використання staticвластивостей.


Ви можете дуже легко передекларувати у дочірньому класі, батьківський клас може бути значенням за замовчуванням, яке використовує дочірній клас, якщо вони не повторно декларують. Якщо ви перебуваєте в батьківському класі, я думаю, це безпечно використовувати self ::, і якщо в дочірньому класі ви можете придумати аргумент, щоб використовувати будь-який, але self :: також буде працювати, якщо ви не розраховуєте на повторно заявити коли-небудь.
Андрій

3
перейдіть на phpfiddle.org і запустіть це<?php class Foo { public static $bar = 1234; public static function a( ) { echo 'static'.static::$bar; echo 'self'.self::$bar; } } class Bar extends Foo { public static $bar = 4321; } (new Bar())->a(); ?>
Євген Афанасьєв

2
Перші два пункти формулювання є заплутаними, мають неоднозначне займенник "це", а також є зайвим, оскільки пізніші абзаци пояснюють ту саму інформацію чіткіше. Я пропоную замінити перші два абзаци на пізніший абзац, який починається з "У вищевказаному сценарії" до початку. Таким чином нижня лінія, відповідь на переслідування, є вгорі. Це зрозуміло і легко слідувати.
ahnbizcad

Ще один спосіб подумати над цим:, self::$abcколи використовується всередині, class Fooце те саме, що говорити Foo::$abc. На це не вплине жодне повторне декларування $abcв підкласі. AFAIK, єдина причина використовувати selfце як скорочення, щоб уникнути використання назви класу Foo, який може бути довшим. [Це також означає, що ви можете змінити ім'я класу, не змінюючи всіх цих місць, але це не є великою причиною IMHO.] (Вибір імен PHP невдалий і здається зворотним; "статичний" - це той, що може змінитися - який протилежне розмовному значенню природничого слова "статичний".)
ToolmakerSteve

4

Як згадувалося, одна з головних відмінностей полягає в тому, що staticдопускаються пізні статичні прив’язки. Один з найкорисніших сценаріїв, який я знайшов, - це створення базових класів для одиночних класів:

class A { // Base Class
    protected static $name = '';
    protected static function getName() {
        return static::$name;
    }
}
class B extends A {
    protected static $name = 'MyCustomNameB';
}
class C extends A {
    protected static $name = 'MyCustomNameC';
}

echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC

Використання return static::$nameв класі Base поверне те, що було приєднано статично при його подовженні. Якщо ви користуєтеся, return self::$nameто B::getName()повертаєте б порожню рядок, оскільки саме це оголошено в класі Base.


0

При selfвиклику:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return self::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "123"
echo (new Bar)->getVar();

Ви можете бачити вище, навіть якщо ми переосмислили $varнаш Barклас, він все одно повертається 123, тому що ми явно попросили PHP для selfзмінної, яка в свою чергу запитує Fooзмінну s.

Тепер, якщо ми поміняємо виклик на static, ми отримаємо Barзамінене значення s:

При staticвиклику:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return static::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "234"
echo (new Bar)->getVar();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.