Наследование — это хорошо зарекомендовавший себя принцип программирования, и 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
{
#[\ReturnTypeWillChange]
public function modify(string $modifier) { return false; }
}
// Уведомление об устаревании не выводится
?>