Abstracción de clases
PHP tiene clases, métodos y propiedades abstractas.
Las clases definidas como abstractas no se pueden instanciar y cualquier clase
que contiene al menos un método abstracto debe ser definida como tal.
Los métodos definidos como abstractos simplemente declaran la firma del método, y si es público o protegido; no pueden definir la implementación.
pero no pueden definir la implementación. Las propiedades definidas como abstractas pueden declarar un requisito para get
o set
, y pueden proporcionar una implementación para una, pero no ambas, operaciones.
Cuando se hereda de una clase abstracta, todos los métodos definidos como abstractos
en la declaración de la clase madre deben ser definidos en la clase hija; además,
estos métodos deben ser definidos con la misma (o con una menos restrictiva)
visibilidad. Por ejemplo,
si el método abstracto está definido como protegido, la implementación de la función
debe ser definida como protegida o pública, pero nunca como privada. Por otra parte,
las firmas de los métodos tienen que coincidir, es decir, la declaración de tipos y el número
de argumentos requeridos deben ser los mismos. Por ejemplo, si la clase derivada
define un argumento opcional y la firma del método abstracto no lo
hace, no habría conflicto con la firma. Esto también se aplica a los constructores
a partir de PHP 5.4. Antes de PHP 5.4, las firmas del constructor podían ser diferentes.
Al heredar de una clase abstracta, todos los métodos marcados como abstractos en la declaración de la clase padre deben ser definidos por la clase hija y seguir las reglas habituales de
herencia y
compatibilidad de firmas.
A partir de PHP 8.4, una clase abstracta puede declarar una propiedad abstracta, ya sea pública o protegida.
Una propiedad abstracta protegida puede ser satisfecha por una propiedad que sea legible/escribible tanto desde el ámbito protegido como público.
Una propiedad abstracta puede ser satisfecha ya sea por una propiedad estándar o por una propiedad con
hooks definidos, correspondientes a la operación requerida.
Ejemplo #1 Ejemplo de clase abstracta
<?php
abstract class ClaseAbstracta
{
// Forzar la extensión de clase para definir este método
abstract protected function getValor();
abstract protected function valorPrefijo($prefijo);
// Método común
public function imprimir() {
print $this->getValor() . "\n";
}
}
class ClaseConcreta1 extends ClaseAbstracta
{
protected function getValor() {
return "ClaseConcreta1";
}
public function valorPrefijo($prefijo) {
return "{$prefijo}ClaseConcreta1";
}
}
class ClaseConcreta2 extends ClaseAbstracta
{
public function getValor() {
return "ClaseConcreta2";
}
public function valorPrefijo($prefijo) {
return "{$prefijo}ClaseConcreta2";
}
}
$clase1 = new ClaseConcreta1;
$clase1->imprimir();
echo $clase1->valorPrefijo('FOO_') ."\n";
$clase2 = new ClaseConcreta2;
$clase2->imprimir();
echo $clase2->valorPrefijo('FOO_') ."\n";
?>
El resultado del ejemplo sería:
ClaseConcreta1
FOO_ClaseConcreta1
ClaseConcreta2
FOO_ClaseConcreta2
Ejemplo #2 Ejemplo de clase abstracta
<?php
abstract class ClaseAbstracta
{
// El método abstracto sólo necesita definir los argumentos requeridos
abstract protected function nombrePrefijo($nombre);
}
class ClaseConcreta extends ClaseAbstracta
{
// La clase derivada puede definir parámetros opcionales que no estén en la estructura del prototipo
public function nombrePrefijo($nombre, $separador = ".") {
if ($nombre == "Pacman") {
$prefijo = "Mr";
} elseif ($nombre == "Pacwoman") {
$prefijo = "Mrs";
} else {
$prefijo = "";
}
return "{$prefijo}{$separador} {$nombre}";
}
}
$clase = new ClaseConcreta;
echo $clase->nombrePrefijo("Pacman"), "\n";
echo $clase->nombrePrefijo("Pacwoman"), "\n";
?>
El resultado del ejemplo sería:
Una propiedad abstracta en una clase abstracta puede proporcionar implementaciones para cualquier hook,
pero debe tener declarado get
o set
, pero no definido (como en el ejemplo anterior).
Ejemplo #3 Ejemplo de propiedad abstracta
<?php
abstract class A
{
// This provides a default (but overridable) set implementation,
// and requires child classes to provide a get implementation.
abstract public string $foo {
get;
set { $this->foo = $value };
}
}
?>