## Herencia de Objetos

La herencia es un principio de programación bien establecido y PHP hace uso de él en su modelado de objetos. Este principio afectará la manera en que muchas clases y objetos se relacionan unas con otras.

Por ejemplo, cuando se extiende una clase, la subclase hereda todos los métodos públicos y protegidos de la clase padre. A menos que una clase sobrescriba esos métodos, mantendrán su funcionalidad original.

Esto es útil para la definición y abstracción de la funcionalidad y permite la implementación de funcionalidad adicional en objetos similares sin la necesidad de reimplementar toda la funcionalidad compartida.

Los métodos privados de una clase padre no son accesibles para una clase hija. Como resultado, las clases hijas pueden reimplementar un método privado sin tener en cuenta las reglas de herencia normales. Antes de PHP 8.0.0, sin embargo, se aplicaban las restricciones `final` y `static` a los métodos privados. A partir de PHP 8.0.0, la única restricción de métodos privados es `private final` que se aplica en el constructor de la clase, ya que es una forma común de "deshabilitar" el constructor cuando es usado en métodos estáticos de fábrica (Patrón Factory).

La visibilidad de los métodos, propiedades y constantes pueden ser relajarse, por ejemplo, un méetodo `protected` puede marcase como `public`, pero no pueden restringirse, por ejemplo. marcando una propiedad `public` como `private`.

> Nota:

> A menos que la carga automática sea utilizada, entonces las clases deben ser definidas antes de ser usadas. Si una clase se extiende a otra, entonces la clase padre debe ser declarada antes de la estructura de clase hija. Esta regla se aplica a las clases que heredan de otras clases e interfaces.

> Nota:

> No está permitido sobrescribir una propiedad de lectura-escritura con una propiedad de sólo lectura o viceversa.

> `<?php
> class A {
> public int $prop;
> }
> class B extends A {
> // Ilegal: lectura-escritura -> sólo lectura
> public readonly int $prop;
> }
> ?>`

Ejemplo #1 Ejemplo de herencia

`<?php
class Foo
{
public function printItem($string)
{
echo 'Foo: ' . $string . PHP_EOL;
}
public function printPHP()
{
echo 'PHP is great.' . PHP_EOL;
}
}
class bar extends Foo
{
public function printItem($string)
{
echo 'Bar: ' . $string . PHP_EOL;
}
}
$foo = new Foo();
$bar = new Bar();
$foo->printItem('baz'); // Salida: 'Foo: baz'
$foo->printPHP(); // Salida: 'PHP is great'
$bar->printItem('baz'); // Salida: 'Bar: baz'
$bar->printPHP(); // Salida: 'PHP is great'
?>`

### Return Type Compatibility with Internal Classes

Prior to PHP 8.1, most internal classes or methods didn't declare their return types, and any return type was allowed when extending them.

As of PHP 8.1.0, most internal methods started to "tentatively" declare their return type, in that case the return type of methods should be compatible with the parent being extended; otherwise, a deprecation notice is emitted. Note that lack of an explicit return declaration is also considered a signature mismatch, and thus results in the deprecation notice.

If the return type cannot be declared for an overriding method due to PHP cross-version compatibility concerns, a `#[ReturnTypeWillChange]` attribute can be added to silence the deprecation notice.

Ejemplo #2 The overriding method does not declare any return type

`<?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" as of PHP 8.1.0
?>`

Ejemplo #3 The overriding method declares a wrong return type

`<?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" as of PHP 8.1.0
?>`

Ejemplo #4 The overriding method declares a wrong return type without a deprecation notice

`<?php
class MyDateTime extends DateTime
{
/**
* @return DateTime|false
*/
#[ReturnTypeWillChange]
public function modify(string $modifier) { return false; }
}
// No notice is triggered
?>`