Новий Я проти нового статичного


513

Я перетворюю бібліотеку PHP 5.3 для роботи над PHP 5.2. Головне, що стоїть на моєму шляху, - це використання пізнього статичного зв’язування, як return new static($options);, наприклад , якщо я перетворять це на те return new self($options), я отримаю ті ж результати?

У чому різниця між new selfі new static?

Відповіді:


889

я отримаю однакові результати?

Не зовсім. Я не знаю, як вирішити PHP 5.2.

У чому різниця між new selfі new static?

selfвідноситься до того ж класу, в якому newнасправді написано ключове слово.

staticу пізніх статичних прив'язках PHP 5.3 посилається на будь-який клас в ієрархії, на який ви назвали метод.

У наступному прикладі Bуспадковується обидва методи від A. selfВиклик пов'язаний з , Aтому що це визначено в Aреалізації «S першого способу, в той час як staticприв'язаний до званого класу (також див get_called_class()).

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

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

class B extends A {}

echo get_class(B::get_self());  // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A

має сенс. Я вважаю, що найкращим є передати ім’я класу функції, яка використовує пізнє статичне прив'язування, а потім повернути новий $ className ($ параметри);
Майк

12
Вам не потрібно "передавати" ім'я класу, ви завжди можете це зробити get_called_class(), що фактично те саме __CLASS__, але сумісне з LSB.
тінь

7
get_called_class не існує в <PHP5.3. Отже, якщо ви хочете отримати ім'я класного об'єкта в PHP5.2 Ця функція не допомагає при спробі перетворити бібліотеку з PHP 5.3 в PHP 5.2
txwikinger

2
Функція, яка називається self: theFunction () поводиться як "я виконуватиму в контексті класу, до якого я фізично належу". а функція, яка називається static :: theFunction () поводиться так, як "я виконую в контексті класу, який насправді викликав зовнішній світ". (Припускаючи сценарій спадкування). Спасибі
Шубраншу

2
У голові я просто беру все, що є інтуїтивно зрозумілим, і роблю це навпаки. Ви можете подумати, що на основі називання selfповернеться і staticповерне щось, що неможливо відмінити ... Але ось ось ось навпаки. Я ніколи не перестаю вражати іменування, конвенції та загальний стиль PHP. -_-
ahnbizcad

23

Якщо метод цього коду не є статичним, ви можете отримати обхід в 5.2, використовуючи get_class($this).

class A {
    public function create1() {
        $class = get_class($this);
        return new $class();
    }
    public function create2() {
        return new static();
    }
}

class B extends A {

}

$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));

Результати:

string(1) "B"
string(1) "B"

17
Якщо метод не є статичним, то пізні статичні прив’язки стають абсолютно неактуальними.
BoltClock

1
Наприклад, ви можете використовувати його в методі "copy", де об'єкт копіюється без використання clone, а лише заново створивши та встановивши властивості. $copy = new static(); $copy->set($this->get()); return $copy;
Маріус Бальчітіс

9
@BoltClock Напевно ні? Якщо ви викликаєте перекритий статичний метод з методу екземпляра підкласу, то ваш вибір self::або static::буде впливати на те, чи буде використана версія цього статичного методу базового класу або підкласу. За відсутності певних причин думати, що така ситуація, яка виникає по суті, вказує на погану практику (і я не бачу жодної причини, чому це повинно бути так), вибір між self::і static::настільки ж актуальний у нестатичних методах, як у статичні методи. Я неправильно зрозумів ваш коментар, чи хтось із нас просто помиляється?
Марк Амері

4
@ Марк Амери: Хм, я про це не думав. Ви абсолютно праві. Я припускав, що жоден статичний метод не буде викликаний у відповідному методі екземпляра, але, виходячи з вашого прикладу, я можу зрозуміти, як це було б дуже наївним припущенням.
BoltClock

Пізні статичні прив’язки doc => php.net/manual/en/language.oop5.late-static-bindings.php
DevWL

7

Окрім відповідей інших:

static :: буде обчислюватися з використанням інформації часу виконання.

Це означає, що ви не можете використовувати static::властивість класу, оскільки значення властивостей:

Повинна бути оцінена під час компіляції та не повинна залежати від інформації про час виконання.

class Foo {
    public $name = static::class;

}

$Foo = new Foo;
echo $Foo->name; // Fatal error

Використання self::

class Foo {
    public $name = self::class;

}
$Foo = new Foo;
echo $Foo->name; // Foo

Зауважте, що коментар Fatal error у зробленому мною коді не вказує, де сталася помилка, помилка сталася раніше, перш ніж об'єкт був ідентифікований як @Grapestain, згаданий у коментарях


4
Зверніть увагу, що помилка подається на рядок 2 public $name = static::class;, а не на рядок 7, як це запропоновано у прикладі. Помилка говорить: "static :: class не може бути використаний для вирішення імені класу часу компіляції", що вказує на проблему не в тому, де ви намагаєтеся отримати доступ до поля $ name, а набагато раніше, при компіляції класу PHP. Рядок 7 (або 6) не буде досягнуто в першому прикладі.
sbnc.eu

@Grapestain Коментар, який я зробив у прикладі, мав показати кінцевий результат, а не вказувати, де насправді сталася помилка. Але все-таки спасибі, що вказали на це.
Дощ

Правильно, я не мав на увазі критикувати, просто уточнив, що спочатку мене бентежило, сподіваючись, що це може допомогти іншим. Корисний приклад все одно!
sbnc.eu
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.