Відповіді:
Вам обов'язково потрібно прочитати пізні статичні прив’язки в посібнику PHP. Однак я спробую дати вам короткий підсумок.
В основному, це зводиться до того, що self
ключове слово не відповідає тим самим правилам успадкування. self
завжди відповідає класу, в якому він використовується. Це означає, що якщо ви робите метод у батьківському класі та називаєте його з дочірнього класу, self
він не посилатиметься на дитину, як ви могли очікувати.
Пізня статична прив'язка вводить нове використання для static
ключового слова, яке вирішує цей конкретний недолік. Коли ви використовуєте static
, він представляє клас, де ви вперше його використовуєте, тобто. він 'прив'язується' до класу виконання.
Це два основних поняття. Шлях self
, parent
і static
працювати , коли static
в грі може бути тонкими, так що замість того , щоб піти , щоб більш детально, я настійно рекомендую вам вивчити керівництво прикладів сторінок. Коли ви зрозумієте основи кожного ключового слова, приклади цілком необхідні, щоб побачити, які результати ви збираєтеся отримати.
self
ключове слово не відповідає правилам успадкування. self
Завжди відповідає класу, в якому воно використовується." - Що не означає, що ви не можете викликати статичний метод батьків від дочірнього об'єкта через self
, як і нестатичні методи. Можливо, ви маєте на увазі правильну річ, але вам слід переформулювати це. Все це має значення лише після того, як діти мають ідентично названі члени, оскільки потім ви можете вирішити, на кого звернутися, використовуючи static::
замість цього.
Від PHP: Пізні статичні прив’язки - Посібник :
Як і в PHP 5.3.0, PHP реалізує функцію, звану пізнім статичним зв'язуванням, яка може бути використана для посилання на названий клас у контексті статичного успадкування.
Пізня статична прив'язка намагається вирішити це обмеження, вводячи ключове слово, яке посилається на клас, який спочатку викликався під час виконання. ... Було вирішено не вводити нове ключове слово, а скоріше використовувати,
static
яке вже було зарезервоване.
Давайте подивимось приклад:
<?php
class Car
{
public static function run()
{
return static::getName();
}
private static function getName()
{
return 'Car';
}
}
class Toyota extends Car
{
public static function getName()
{
return 'Toyota';
}
}
echo Car::run(); // Output: Car
echo Toyota::run(); // Output: Toyota
?>
Пізні статичні прив'язки працюють, зберігаючи клас, названий в останньому "непереадресувальному дзвінку". У разі викликів статичних методів це клас, явно названий (як правило, ліворуч від
::
оператора); у випадку нестатичних викликів методу - це клас об'єкта. А «переадресація виклику» є статичним , який вводитьсяself::
,parent::
,static::
або, якщо йти вгору в ієрархії класів,forward_static_call()
. Функціяget_called_class()
може бути використана для отримання рядка з назвою класу, що викликається, таstatic::
введення його області.
Не дуже очевидна поведінка:
У наведеному нижче коді створюється "alphabeta".
class alpha {
function classname(){
return __CLASS__;
}
function selfname(){
return self::classname();
}
function staticname(){
return static::classname();
}
}
class beta extends alpha {
function classname(){
return __CLASS__;
}
}
$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta
Однак якщо ми видалимо декларацію функції classname з бета-класу, в результаті отримаємо 'alphaalpha'.
Я цитую з книги: "PHP Master написати передовий код".
Пізнє статичне зв'язування було особливістю, введеною в php 5.3. Це дозволяє нам успадковувати статичні методи від батьківського класу та посилатись на дочірній клас, який викликається.
Це означає, що ви можете мати абстрактний клас зі статичними методами та посилатися на конкретні реалізації дочірнього класу, використовуючи позначення static :: method () замість методу self :: ().
Не соромтеся також ознайомитися з офіційною документацією на php: http://php.net/manual/en/language.oop5.late-static-bindings.php
Найясніший спосіб пояснити пізнє статичне зв’язування - простим прикладом. Погляньте на два визначення класу нижче та прочитайте далі.
class Vehicle {
public static function invokeDriveByStatic() {
return static::drive(); // Late Static Binding
}
public static function invokeStopBySelf() {
return self::stop(); // NOT Late Static Binding
}
private static function drive(){
return "I'm driving a VEHICLE";
}
private static function stop(){
return "I'm stopping a VEHICLE";
}
}
class Car extends Vehicle {
protected static function drive(){
return "I'm driving a CAR";
}
private static function stop(){
return "I'm stopping a CAR";
}
}
Ми бачимо клас батьків (транспортний засіб) та дитячий клас (автомобіль). У батьківського класу є 2 загальнодоступних методу:
invokeDriveByStatic
invokeStopBySelf
У батьківського класу також є 2 приватних методу:
drive
stop
Дочірній клас перекриває 2 методи:
drive
stop
Тепер давайте звернемось до публічних методів:
invokeDriveByStatic
invokeStopBySelf
Запитайте себе: який клас викликає invokeDriveByStatic
/ invokeStopBySelf
? Клас для батьків або дітей?
Подивіться нижче:
// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a VEHICLE
echo Vehicle::invokeStopBySelf(); // I'm stopping a VEHICLE
// !!! This is Late Static Binding !!!!
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR
// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a VEHICLE
static
Ключове слово використовується в шаблоні проектування Singleton. Посилання: https://refactoring.guru/design-patterns/singleton/php/example
Найпростіший приклад показати різницю.
Зауважте, самості: $ c
class A
{
static $c = 7;
public static function getVal()
{
return self::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 7
Пізня статична прив'язка, примітка статична :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return static::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 8
Також слідкуйте за тим, чи оновлюєте статичні змінні в дочірніх класах. Я знайшов цей (дещо) несподіваний результат, коли дитина B оновлює дитину C:
class A{
protected static $things;
}
class B extends A {
public static function things(){
static::$things[1] = 'Thing B';
return static::$things;
}
}
class C extends A{
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}
print_r(C::things());
// Array (
// [2] => Thing C
// )
B::things();
print_r(C::things());
// Array (
// [2] => Thing C
// [1] => Thing B
// )
Ви можете виправити це, оголосивши ту саму змінну у кожному дочірньому класі, наприклад:
class C extends A{
protected static $things; // add this and B will not interfere!
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}