Sobrescritura de métodos revisada
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 33 de 91.
Ya has aprendido sobre la sobrescritura de métodos en el capítulo de Herencia. Ahora exploremos cómo se conecta con el polimorfismo, uno de los conceptos más potentes de la programación orientada a objetos.
El polimorfismo significa "muchas formas". Cuando sobrescribes un método en una clase hija, le estás dando a ese método una forma diferente mientras mantienes el mismo nombre. La magia ocurre cuando trabajas con objetos a través de su tipo padre:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()) . "\n";
echo makeAnimalSpeak(new Cat());
Resultado:
Woof!
Meow!La función makeAnimalSpeak() acepta cualquier Animal. No sabe ni le importa si recibe un Dog o un Cat. PHP llama automáticamente al método sobrescrito correcto basándose en el tipo de objeto real en tiempo de ejecución.
Esto es polimorfismo en acción.
Este enfoque le permite escribir código flexible que funciona con una familia de objetos relacionados sin conocer sus tipos específicos. Puede agregar nuevas clases de animales más tarde, y la función funcionará con ellas automáticamente.
Punto clave: La sobrescritura de métodos permite el polimorfismo al permitir que diferentes clases respondan de manera distinta a la misma llamada de método, determinada en tiempo de ejecución por el tipo de objeto real.
Desafío
FácilVamos a construir un sistema de instrumentos musicales que demuestre el polimorfismo a través de la sobrescritura de métodos. Crearás una clase base Instrument y dos clases hijas que produzcan cada una su propio sonido único; luego, usarás una única función para tocar cualquier instrumento de forma polimórfica.
Organizarás tu código en cuatro archivos:
Instrument.php— Crea una claseInstrumentcon una propiedad protegida$nameestablecida a través del constructor. Agrega un métodoplay()que devuelva"[name] makes a sound". Esto sirve como el comportamiento base que las clases hijas sobrescribirán.Guitar.php— Crea una claseGuitarque extienda deInstrument. Incluye el archivo del padre. El constructor acepta el nombre y lo pasa al constructor del padre. Sobrescribe el métodoplay()para que devuelva"[name] strums a chord".Drum.php— Crea una claseDrumque extienda deInstrument. Incluye el archivo del padre. El constructor acepta el nombre y lo pasa al constructor del padre. Sobrescribe el métodoplay()para que devuelva"[name] beats a rhythm".main.php— Incluye los archivos de Guitar y Drum. Crea una función llamadaperformWithque acepte un parámetroInstrument(con sugerencia de tipo o type-hint) y devuelva el resultado de llamar aplay()en él. Esta función demuestra el polimorfismo: funciona con cualquier tipo de instrumento a través de la sugerencia de tipo de la clase padre.
Recibirás dos entradas: un nombre para la guitarra y un nombre para el tambor. Crea una Guitar y un Drum con estos nombres. Pasa cada uno a tu función performWith() e imprime los resultados: primero la guitarra, luego el tambor, cada uno en su propia línea.
Observa cómo performWith() acepta cualquier Instrument, pero PHP llama automáticamente al método play() sobrescrito correcto basándose en el tipo de objeto real en tiempo de ejecución. ¡Eso es el polimorfismo en acción!
Hoja de referencia
El polimorfismo significa "muchas formas" y permite que objetos de diferentes clases sean tratados a través de su tipo padre manteniendo su comportamiento específico.
Cuando sobrescribes un método en clases hijas, PHP llama automáticamente a la versión correcta basándose en el tipo de objeto real en tiempo de ejecución:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()); // Woof!
echo makeAnimalSpeak(new Cat()); // Meow!
La función makeAnimalSpeak() acepta cualquier tipo Animal a través de su sugerencia de tipo de parámetro. No necesita conocer la clase específica: PHP determina qué método sobrescrito llamar en tiempo de ejecución basándose en el tipo de objeto real.
Esto permite un código flexible que funciona con una familia de objetos relacionados sin conocer sus tipos específicos. Se pueden añadir nuevas clases hijas más tarde y funcionarán automáticamente con las funciones existentes.
Pruébalo tú mismo
<?php
// Incluir los archivos de instrumentos
require_once 'Guitar.php';
require_once 'Drum.php';
// Leer la entrada
$guitarName = trim(fgets(STDIN));
$drumName = trim(fgets(STDIN));
// TODO: Crear una función llamada performWith que:
// - Acepte un parámetro Instrument (usar sugerencia de tipo: Instrument $instrument)
// - Devuelva el resultado de llamar a play() en el instrumento
// TODO: Crear una Guitar con $guitarName y un Drum con $drumName
// TODO: Pasar cada uno a performWith() e imprimir los resultados (guitarra primero, luego tambor)
?>Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a OOPClases vs ObjetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Resumen - Calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasResumen - Jerarquía de empleados7Encapsulamiento
Público, Protegido, PrivadoModificadores de acceso a fondoGetters y SettersOcultamiento de informaciónPromoción de constructor (8.0)Resumen - Sistema de registros de estudiantes10Conceptos avanzados de POO
Composición vs. HerenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibers (PHP 8.1)Clonación de objetos a fondoGeneradores e Iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Espacios de nombres y Autoloading
Introducción a los espacios de nombresLa palabra clave useEstándar de Autoloading PSR-4Autoloader de ComposerResumen - Proyecto organizado5Interfaces y Contratos
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesInterfaz vs Clase AbstractaType Hinting con InterfacesResumen - Calculadora de Formas8Métodos mágicos
Introducción a los métodos mágicos__toString y __debugInfo__get, __set, __isset, __unset__call y __callStatic__clone y clonación de objetos__serialize y __unserializeResumen - Colección personalizada3Propiedades de clase
Propiedades de instancia vs. estáticasConstantes en clasesMétodos y propiedades estáticosPropiedades privadas y protegidasPropiedades de solo lectura (PHP 8.1)Resumen - Gestor de cuenta bancaria6Polimorfismo
Sobrescritura de métodos revisadaPolimorfismo mediante interfacesType Hinting y tipos de uniónEnlace estático tardíoResumen - Procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos de TraitsMétodos abstractos en TraitsTraits frente a herencia12Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy