Herencia

La herencia es uno de los grandes principios de la programación orientada a objetos (POO), y PHP la implementa en su modelo de objetos. Este principio afectará la manera en que muchas clases están relacionadas entre sí.

Por ejemplo, cuando una clase es extendida, la clase hija hereda todas las métodos públicos y protegidos, propiedades y constantes de la clase padre. Mientras una clase no sobrescriba estos métodos, conservan su funcionalidad original.

La herencia es muy útil para definir y abstraer ciertas funcionalidades comunes a varias clases, permitiendo al mismo tiempo la implementación de funcionalidades adicionales en las clases hijas, sin tener que reimplementar en su interior todas las funcionalidades comunes.

Los métodos privados de una clase padre no son accesibles para la clase hija. Por consiguiente, las clases hijas pueden reimplementar un método privado por sí mismas sin preocuparse por las reglas normales de herencia. Anterior a PHP 8.0.0, sin embargo, las restricciones final y static se aplicaban a los métodos privados. A partir de PHP 8.0.0, la única restricción de método privado que se impone es private final en los constructores, ya que es una manera común para "desactivar" el constructor cuando se utilizan métodos de fábrica estáticos en su lugar.

La visibilidad de los métodos, propiedades y constantes puede ser relajada, es decir, un método protected puede ser marcado como public, pero no pueden ser restringidos, por ejemplo, marcar una propiedad public como private. Una excepción son los constructores, para los cuales la visibilidad puede ser restringida, por ejemplo, un constructor public puede ser anotado como private en la clase hija.

Nota:

A menos que se utilice la autocarga, las clases deben ser conocidas antes de ser utilizadas. Las clases padres deben ser definidas antes de escribir una herencia. Esta regla general se aplica también en el caso de herencia o implementación de interfaces.

Nota:

No está permitido redefinir una propiedad de lectura-escritura con una propiedad de solo lectura o viceversa.

<?php

class A {
public
int $prop;
}
class
B extends A {
// Ilegal: read-write -> readonly
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 es genial' . PHP_EOL;
}
}

class
Bar extends Foo
{
public function
printItem($string)
{
echo
'Bar: ' . $string . PHP_EOL;
}
}

$foo = new Foo();
$bar = new Bar();
$foo->printItem('baz'); // Muestra: 'Foo: baz'
$foo->printPHP(); // Muestra: 'PHP es genial'
$bar->printItem('baz'); // Muestra: 'Bar: baz'
$bar->printPHP(); // Muestra: 'PHP es genial'

?>

Compatibilidad de los tipos de retorno con las clases internas

Anterior a PHP 8.1, la mayoría de las clases o métodos internos no declaraban su tipo de retorno, y cualquier tipo de retorno estaba permitido al heredarlos.

A partir de PHP 8.1.0, la mayoría de los métodos internos comenzaron a declarar "provisionalmente" su tipo de retorno, en este caso, el tipo de retorno de los métodos debe ser compatible con la clase padre; en caso contrario, se emite una notificación de deprecación. Tenga en cuenta que la ausencia de una declaración de retorno explícita también se considera un error de firma, y por lo tanto provoca el aviso de deprecación.

Si el tipo de retorno no puede ser declarado para un método de sobrecarga debido a problemas de compatibilidad entre versiones de PHP, un atributo ReturnTypeWillChange puede ser añadido para silenciar el aviso de deprecación.

Ejemplo #2 El método sobrecargado no declara tipo de retorno.

<?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" A partir de PHP 8.1.0

Ejemplo #3 El método sobrecargado declara un tipo de retorno incorrecto.

<?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" A partir de PHP 8.1.0

Ejemplo #4 El método sobrecargado declara un tipo de retorno incorrecto sin aviso de deprecación.

<?php

class MyDateTime extends DateTime
{
/**
* @return DateTime|false
*/
#[\ReturnTypeWillChange]
public function
modify(string $modifier) { return false; }
}

// No se emite ningún aviso
add a note

User Contributed Notes 6 notes

up
214
jackdracona at msn dot com
15 years ago
Here is some clarification about PHP inheritance – there is a lot of bad information on the net. PHP does support Multi-level inheritance. (I tested it using version 5.2.9). It does not support multiple inheritance.

This means that you cannot have one class extend 2 other classes (see the extends keyword). However, you can have one class extend another, which extends another, and so on.

Example:

<?php
class A {
// more code here
}

class
B extends A {
// more code here
}

class
C extends B {
// more code here
}


$someObj = new A(); // no problems
$someOtherObj = new B(); // no problems
$lastObj = new C(); // still no problems

?>
up
102
Mohammad Istanbouly
7 years ago
I think the best way for beginners to understand inheritance is through a real example so here is a simple example I can gave to you

<?php

class Person
{
public
$name;
protected
$age;
private
$phone;

public function
talk(){
//Do stuff here
}

protected function
walk(){
//Do stuff here
}

private function
swim(){
//Do stuff here
}
}

class
Tom extends Person
{
/*Since Tom class extends Person class this means
that class Tom is a child class and class person is
the parent class and child class will inherit all public
and protected members(properties and methods) from
the parent class*/

/*So class Tom will have these properties and methods*/

//public $name;
//protected $age;
//public function talk(){}
//protected function walk(){}

//but it will not inherit the private members
//this is all what Object inheritance means
}
up
19
akashwebdev at gmail dot com
9 years ago
The Idea that multiple inheritence is not supported is correct but with tratits this can be reviewed.

for e.g.

<?php
trait custom
{
public function
hello()
{
echo
"hello";
}
}

trait
custom2
{
public function
hello()
{
echo
"hello2";
}
}

class
inheritsCustom
{
use
custom, custom2
{
custom2::hello insteadof custom;
}
}

$obj = new inheritsCustom();
$obj->hello();
?>
up
15
jarrod at squarecrow dot com
15 years ago
You can force a class to be strictly an inheritable class by using the "abstract" keyword. When you define a class with abstract, any attempt to instantiate a separate instance of it will result in a fatal error. This is useful for situations like a base class where it would be inherited by multiple child classes yet you want to restrict the ability to instantiate it by itself.

Example........

<?php

abstract class Cheese
{
//can ONLY be inherited by another class
}

class
Cheddar extends Cheese
{
}

$dinner = new Cheese; //fatal error
$lunch = new Cheddar; //works!

?>
up
17
strata_ranger at hotmail dot com
14 years ago
I was recently extending a PEAR class when I encountered a situation where I wanted to call a constructor two levels up the class hierarchy, ignoring the immediate parent. In such a case, you need to explicitly reference the class name using the :: operator.

Fortunately, just like using the 'parent' keyword PHP correctly recognizes that you are calling the function from a protected context inside the object's class hierarchy.

E.g:

<?php
class foo
{
public function
something()
{
echo
__CLASS__; // foo
var_dump($this);
}
}

class
foo_bar extends foo
{
public function
something()
{
echo
__CLASS__; // foo_bar
var_dump($this);
}
}

class
foo_bar_baz extends foo_bar
{
public function
something()
{
echo
__CLASS__; // foo_bar_baz
var_dump($this);
}

public function
call()
{
echo
self::something(); // self
echo parent::something(); // parent
echo foo::something(); // grandparent
}
}

error_reporting(-1);

$obj = new foo_bar_baz();
$obj->call();

// Output similar to:
// foo_bar_baz
// object(foo_bar_baz)[1]
// foo_bar
// object(foo_bar_baz)[1]
// foo
// object(foo_bar_baz)[1]

?>
up
1
ignacio at inek dot com dot ar
3 months ago
In case you have a public readonly property in a class you need to extend, adding other properties, this can be a way to do it:

<?php

class A {
public function
__construct(
public readonly
int $prop
) {}
}

class
B extends A {
public function
__construct(
int $prop,
public readonly
int $prop2
) {
parent::__construct($prop);
}
}
?>
To Top