En capítulo pasados hablábamos sobre la herencia, la cual consiste en que nosotros podemos definir una clase padre, la cual tiene cierta cantidad de propiedades y métodos, y posteriormente definir otras clases, las cuales extendían de la clase padre, heredando tanto sus propiedades como sus métodos.
En PHP la herencia es simple, lo que significa que una clase sólo puede heredar de una y sólo una clase padre. Existen otros lenguajes orientados a objetos, como son C++, que permiten que una clase hija herede de varias clases padre, pero no es el caso de PHP.
Simular herencia múltiple
Para simular la herencia múltiple, en PHP podemos hacer uso de los traits.
Ejm
<?php
class Persona {
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function getNombre(){
return ucwords($this->nombre);
}
}
trait Latinoamericano {
public function saludoLatinoamericano(){
echo "Este es un saludo latinoamericano"
}
}
trait Europeo {
public function saludoEuropeo(){
echo "Este es un saludo europeo";
}
}
class Peruano extends Persona {
use Lainoamericano;
// Con esto conseguimos que herede tanto de la clase Persona como de la clase Latinoamericano
}
class Aleman extends Persona {
use Europeo;
// Con esto conseguimos que herede tanto de la clase Persona como de la clase Europeo
}
$peruano = new Peruano;
$peruano->saludoLatinoamericano();
Una de las principales diferencias entre una clase y un trait es que los traits no se pueden instanciar. Los traits sólo se van a utilizar para poder extender las propiedades y métodos de una determinada clase.
Presencia
Cuando implementamos un trait, éste sobreescribe cualquier método de la clase padre que lleve el mismo nombre.
Ejm
<?php
class Persona {
public $nombre;
public function saludo(){
echo "Hola";
}
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function getNombre(){
return ucwords($this->nombre);
}
}
trait Latinoamericano {
public function saludo(){
echo "Hola Mundo";
}
}
class Peruano extends Persona {
use Lainoamericano;
// Con esto conseguimos que herede tanto de la clase Persona como de la clase Latinoamericano
}
$peruano = new Peruano;
$peruano->saludo();
Igualmente, si existe el mismo método en la clase hija que hereda tanto de la clase padre como del trait, ese será el método que se ejecutará si instanciamos sobre la clase hija, es decir, el método de la clase hija sobreescribirá el de la clase padre y el del trait, al igual que el método del trait ha sobreescrito el de la clase padre.
Ejm
<?php
class Persona {
public $nombre;
public function saludo(){
echo "Hola";
}
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function getNombre(){
return ucwords($this->nombre);
}
}
trait Latinoamericano {
public function saludo(){
echo "Hola Mundo";
}
}
class Peruano extends Persona {
use Lainoamericano;
// Con esto conseguimos que herede tanto de la clase Persona como de la clase Latinoamericano
public function saludo(){
echo "Hola Mundo desde la clase peruano";
}
}
$peruano = new Peruano;
$peruano->saludo();
Uso de más de un trait
Para ello utilizamos la sintaxis del ejm.
Ejm
<?php
class Persona {
public $nombre;
public function saludo(){
echo "Hola";
}
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function getNombre(){
return ucwords($this->nombre);
}
}
trait hola {
public function decirHola(){
echo "Hola";
}
}
trait mundo {
public function decirMundo(){
echo "mundo";
}
}
class Peruano extends Persona {
use hola, mundo;
// Con esto conseguimos que herede tanto de la clase Persona como de las traits hola y mundo
public function saludo(){
echo "Hola Mundo desde la clase peruano";
}
}
$peruano = new Peruano;
$peruano->decirHola();
$peruano->decirMundo(); // Imprimirá hola mundo
Uso de mismos métodos en los traits
Si tenemos dos traits que utilizan un método con el mismo nombre, dichos métodos entrarán en conflicto, para ello podemos utilizar la sintaxis del siguiente ejm para elegir uno de los métodos.
Ejm
<?php
class Persona {
public $nombre;
public function saludo(){
echo "Hola";
}
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function getNombre(){
return ucwords($this->nombre);
}
}
trait A {
public function saludo(){
echo "Hola mundo desde el trait A";
}
}
trait B {
public function saludo(){
echo "Hola mundo desde el trait B";
}
class Peruano extends Persona {
use A, B {
// Queremos utilizar el método saludo del trait A y no del trait B
A::saludo insteadOf B;
}
// Con esto conseguimos que herede tanto de la clase Persona como de las traits hola y mundo
public function saludo(){
echo "Hola Mundo desde la clase peruano";
}
}
$peruano = new Peruano;
$peruano->decirHola();
$peruano->decirMundo(); // Imprimirá hola mundo
Métodos protegidos en traits
Si queremos que un método protegido en un trait se transforme en público podemos utilizar la sintaxis del siguiente ejm.
Ejm
<?php
class Persona {
public $nombre;
public function saludo(){
echo "Hola";
}
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function getNombre(){
return ucwords($this->nombre);
}
}
trait A {
protected function saludo(){
echo "Hola mundo desde el trait A";
}
}
class Peruano extends Persona {
use A { saludo as public; }
}
$peruano = new Peruano;
$peruano->saludo();
Uso de traits compuestos de otros traits
Podemos usar traits compuestos de otros traits mediante la siguiente sintaxis.
Ejm
<?php
class Persona {
public $nombre;
public function saludo(){
echo "Hola";
}
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function getNombre(){
return ucwords($this->nombre);
}
}
trait A {
public function decirHola(){
echo "Hola";
}
}
trait B {
public function decirMundo(){
echo "Mundo";
}
}
trait C {
use A, B;
}
class Peruano extends Persona {
use C;
}
$peruano = new Peruano;
$peruano->decirHola();
$peruano->decirMundo();
Métodos abstractos
En los traits también podemos definir métodos abstractos.
Ejm
<?php
class Persona {
public $nombre;
public function saludo(){
echo "Hola";
}
public function setNombre($nombre){
$this->nombre = $nombre;
}
public function getNombre(){
return ucwords($this->nombre);
}
}
trait A {
public function decirHola(){
echo "Hola";
}
}
trait B {
public function decirMundo(){
echo "Mundo";
}
abstract public function saludar();
}
trait C {
use A, B;
public function saludar(){
$this->decirHola();
$this->decirMundo();
}
}
class Peruano extends Persona {
use C;
}
$peruano = new Peruano;
$peruano->saludar();
a