Наследование
Наследование — это хорошо зарекомендовавший себя принцип программирования, и PHP
использует этот принцип в своей объектной модели. Этот принцип повлияет на то,
как многие классы и объекты связаны друг с другом.
Например, при расширении класса дочерний класс наследует все
общедоступные и защищённые методы, свойства и константы родительского класса.
До тех пор пока
эти методы не будут переопределены, они будут сохранять свою
исходную функциональность.
Это полезно для определения и абстрагирования функциональности и позволяет
реализовать дополнительную функциональность в похожих объектах без
необходимости реализовывать всю общую функциональность.
Закрытые методы родительского класса недоступны для дочернего класса. В результате
дочерние классы могут повторно реализовать закрытый метод без учёта обычных
правил наследования. Однако до PHP 8.0.0 к закрытым методам применялись ограничения
final
и static
. Начиная с PHP 8.0.0,
единственное ограничение закрытого метода, которое применяется - это конструкторы private final
,
поскольку это обычный способ "отключить" конструктор при использовании вместо него статичных фабричных методов.
Видимость методов,
свойств и констант можно ослабить, например, защищённый
метод
может быть помечен как общедоступный
, но нельзя ограничить видимость,
например, нельзя пометить общедоступное
свойство как закрытое
.
Исключением являются конструкторы, видимость которых может быть ограничена,
например, общедоступный
конструктор может быть помечен
как закрытый
в дочернем классе.
Замечание:
Если не используется автозагрузка, классы должны быть объявлены до того, как они
будут использоваться. Если класс расширяет другой, то родительский класс должен быть
объявлен до наследующего класса. Это правило применяется к классам, которые наследуют
другие классы или интерфейсы.
Замечание:
Не разрешается переопределять свойство чтения-записи с помощью readonly-свойства или наоборот.
<?php
class A {
public int $prop;
}
class B extends A {
// Нельзя: read-write -> readonly
public readonly int $prop;
}
?>
Пример #1 Пример наследования
<?php
class Foo
{
public function printItem($string)
{
echo 'Foo: ' . $string . PHP_EOL;
}
public function printPHP()
{
echo 'PHP просто супер.' . PHP_EOL;
}
}
class Bar extends Foo
{
public function printItem($string)
{
echo 'Bar: ' . $string . PHP_EOL;
}
}
$foo = new Foo();
$bar = new Bar();
$foo->printItem('baz'); // Выведет: 'Foo: baz'
$foo->printPHP(); // Выведет: 'PHP просто супер'
$bar->printItem('baz'); // Выведет: 'Bar: baz'
$bar->printPHP(); // Выведет: 'PHP просто супер'
?>
Совместимость типов возвращаемых значений с внутренними классами
До PHP 8.1.0 большинство внутренних классов или методов не объявляли свои типы возвращаемых значений
и при их расширении допускался любой тип возвращаемого значения.
Начиная с PHP 8.1.0, большинство внутренних методов начали "предварительно" объявлять тип возвращаемого значения.
В этом случае тип возвращаемого значения методов должен быть совместим с расширяемым родителем;
в противном случае выдаётся уведомление об устаревании.
Обратите внимание, что отсутствие явного объявления типа возвращаемого значения также считается несоответствием сигнатуры
и, соответственно, приводит к уведомлению об устаревании.
Если тип возвращаемого значения не может быть объявлен для переопределяемого метода из-за проблем с совместимостью
с различными версиями PHP, может быть добавлен атрибут ReturnTypeWillChange, чтобы заглушить уведомление об устаревании.
Пример #2 Переопределяющий метод не объявляет никакого типа возвращаемого значения
<?php
class MyDateTime extends DateTime
{
public function modify(string $modifier) { return false; }
}
// "Deprecated: Return type of MyDateTime::modify(string $modifier) should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice", начиная с PHP 8.1.0
?>
Пример #3 Переопределяющий метод объявляет неверный тип возвращаемого значения
<?php
class MyDateTime extends DateTime
{
public function modify(string $modifier): ?DateTime { return null; }
}
// "Deprecated: Return type of MyDateTime::modify(string $modifier): ?DateTime should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice", начиная с PHP 8.1.0
?>
Пример #4 Переопределяющий метод объявляет неверный тип возвращаемого значения без уведомления об устаревании
<?php
class MyDateTime extends DateTime
{
/**
* @return DateTime|false
*/
#[\ReturnTypeWillChange]
public function modify(string $modifier) { return false; }
}
// Уведомление об устаревании не выводится
?>