Clases abstractas
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 25 de 91.
Una clase abstracta es una clase que no se puede instanciar directamente. Sirve como un plano para otras clases, definiendo métodos que las clases hijas deben implementar. Se crea una clase abstracta utilizando la palabra clave abstract.
<?php
abstract class Shape {
protected $color;
public function __construct($color) {
$this->color = $color;
}
abstract public function calculateArea();
public function getColor() {
return $this->color;
}
}
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($color, $width, $height) {
parent::__construct($color);
$this->width = $width;
$this->height = $height;
}
public function calculateArea() {
return $this->width * $this->height;
}
}
$rect = new Rectangle("blue", 5, 3);
echo $rect->calculateArea();
Resultado:
15La clase Shape declara un método abstracto calculateArea() sin proporcionar una implementación. Cualquier clase que extienda Shape debe implementar este método. Observa que las clases abstractas también pueden contener métodos regulares como getColor() que las clases hijas heredan directamente.
Los métodos abstractos definen lo que una clase hija debe hacer, pero no cómo. Esto asegura que todas las formas tengan un método calculateArea() mientras permite que cada forma calcule su área de manera diferente.
Punto clave: Las clases abstractas combinan la estructura de la herencia con requisitos obligatorios. Úsalas cuando quieras compartir código entre clases relacionadas y, al mismo tiempo, asegurar que cada clase hija implemente ciertos métodos.
Desafío
FácilConstruyamos un sistema de reproductor de medios que demuestre cómo las clases abstractas imponen un contrato mientras permiten que diferentes tipos de medios implementen su propio comportamiento de reproducción.
Organizarás tu código en tres archivos:
Media.php— Define una clase abstractaMediaque sirva como plano para todos los tipos de medios. Debe tener una propiedad protegida$titley un constructor que acepte y establezca el título. Incluye un método abstracto llamadoplay()que las clases hijas deben implementar. También añade un método regulargetTitle()que devuelva el título — este método concreto será heredado por todas las clases hijas.Song.php— Define una claseSongque extienda deMedia. Incluye el archivo Media al principio. Esta clase añade una propiedad$artist. El constructor debe aceptar el título y el artista — usaparent::__construct()para el título, luego establece el artista tú mismo. Implementa el métodoplay()requerido para que devuelva"Playing song: [title] by [artist]".Podcast.php— Define una clasePodcastque extienda deMedia. Incluye el archivo Media al principio. Esta clase añade una propiedad$episode(un entero). El constructor debe aceptar el título y el número de episodio — usaparent::__construct()para el título, luego establece el episodio. Implementa el métodoplay()requerido para que devuelva"Playing podcast: [title] - Episode [episode]".
En main.php, incluye tanto el archivo de Song como el de Podcast. Recibirás cuatro entradas: el título de la canción, el nombre del artista, el título del podcast y el número de episodio (como una cadena para convertir a entero). Crea un objeto Song y un objeto Podcast con estos valores. Imprime el resultado de llamar a play() en la canción primero, luego en el podcast, cada uno en su propia línea.
Este desafío muestra cómo las clases abstractas definen un contrato — cada tipo de medio debe tener un método play(), pero cada tipo lo implementa de manera diferente. La clase abstracta Media no puede ser instanciada directamente; solo existe para proporcionar estructura y funcionalidad compartida a sus hijos.
Hoja de referencia
Una clase abstracta es una clase que no se puede instanciar directamente. Sirve como un plano para otras clases, definiendo métodos que las clases hijas deben implementar. Utilice la palabra clave abstract para crear una clase abstracta.
abstract class Shape {
protected $color;
public function __construct($color) {
$this->color = $color;
}
abstract public function calculateArea();
public function getColor() {
return $this->color;
}
}Las clases hijas deben implementar todos los métodos abstractos:
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($color, $width, $height) {
parent::__construct($color);
$this->width = $width;
$this->height = $height;
}
public function calculateArea() {
return $this->width * $this->height;
}
}Características clave:
- Las clases abstractas no se pueden instanciar directamente
- Los métodos abstractos no tienen implementación en la clase abstracta
- Las clases hijas deben implementar todos los métodos abstractos
- Las clases abstractas pueden contener tanto métodos abstractos como regulares
- Los métodos regulares en las clases abstractas son heredados por las clases hijas
Pruébalo tú mismo
<?php
require_once 'Song.php';
require_once 'Podcast.php';
// Leer entradas
$songTitle = trim(fgets(STDIN));
$artistName = trim(fgets(STDIN));
$podcastTitle = trim(fgets(STDIN));
$episodeNumber = intval(trim(fgets(STDIN)));
// TODO: Crear un objeto Song con songTitle y artistName
// TODO: Crear un objeto Podcast con podcastTitle y episodeNumber
// TODO: Imprimir el resultado de llamar a play() en la canción
// TODO: Imprimir el resultado de llamar a play() en el podcast
?>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