O PHP possui métodos, classes e propriedades abstratas. Classes definidas como
abstratas não podem ser instanciadas, e qualquer classe que
contenha ao menos um método abstrato ou uma propriedade abstrata também deve ser abstrata.
Métodos definidos como abstratos simplesmente declaram a assinatura e se ele é público ou protegido;
eles não podem definir a implementação. Propriedade definidas como abstratas
podem declarar um requisito para o comportamento de get
ou set
,
e podem fornecer uma implementação para uma das operações, mas não para ambas.
Quando herdando de uma classe abstrata, todos os métodos marcados como abstratos da classe herdada precisam ser definidos na classe implementante. além de seguir as regras usuais de herança e compatibilidade de assinatura.
A partir do PHP 8.4, uma classe abstrata pode declarar uma propriedade abstrata, seja pública ou protegida. Uma propriedade abstrata protegida pode ser satisfeita por uma propriedade que pode ser lida/gravada no escopo protegido ou público.
Uma propriedade abstrata pode ser satisfeita por uma propriedade padrão ou por uma propriedade com ganchos definidos, correspondentes à operação necessária.
Exemplo #1 Exemplo de método abstrato
<?php
abstract class ClasseAbstrata
{
// Força a classe que estende ClasseAbstrata a definir esse método
abstract protected function pegarValor();
abstract protected function valorComPrefixo( $prefixo );
// Método comum
public function imprimir()
{
print $this->pegarValor();
}
}
class ClasseConcreta1 extends ClasseAbstrata
{
protected function pegarValor()
{
return "ClasseConcreta1";
}
public function valorComPrefixo( $prefixo )
{
return "{$prefixo}ClasseConcreta1";
}
}
class ClasseConcreta2 extends ClasseAbstrata
{
protected function pegarValor()
{
return "ClasseConcreta2";
}
public function valorComPrefixo( $prefixo )
{
return "{$prefixo}ClasseConcreta2";
}
}
$classe1 = new ClasseConcreta1();
$classe1->imprimir();
echo $classe1->valorComPrefixo('FOO_'), "\n";
$classe2 = new ClasseConcreta2();
$classe2->imprimir();
echo $classe2->valorComPrefixo('FOO_'), "\n";
?>
O exemplo acima produzirá:
ConcreteClass1 FOO_ConcreteClass1 ConcreteClass2 FOO_ConcreteClass2
Exemplo #2 Exemplo de método abstrato
<?php
abstract class ClasseAbstrata
{
// Um método abstrato precisa definir apenas os parâmetros requeridos
abstract protected function prefixName($name);
}
class ClasseConcreta extends ClasseAbstrata
{
// Uma classe filha pode definir parâmetros opcionais que não estão presentes na assitura da classe superior
public function prefixName($name, $separator = ".")
{
if ($name == "Pacman") {
$prefix = "Mr";
} elseif ($name == "Pacwoman") {
$prefix = "Mrs";
} else {
$prefix = "";
}
return "{$prefix}{$separator} {$name}";
}
}
$class = new ClasseConcreta();
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";
?>
O exemplo acima produzirá:
Mr. Pacman Mrs. Pacwoman
Exemplo #3 Exemplo de propriedade abstrata
<?php
abstract class A
{
// A extensão de classes deve ter uma propriedade que pode ser obtida publicamente.
abstract public string $readable {
get;
}
// A extensão de classes deve ter uma propriedade gravável protegida ou pública.
abstract protected string $writeable {
set;
}
// A extensão de classes deve ter uma propriedade simétrica protegida ou pública.
abstract protected string $both {
get;
set;
}
}
class C extends A
{
// Isto satisfaz o requisito e também o torna configurável, o que é válido.
public string $readable;
// Isso NÃO satisfaria o requisito, pois não é legível publicamente.
protected string $readable;
// Isso satisfaz exatamente o requisito, portanto é suficiente.
// Pode ser alterado, somente a partir do escopo protegido.
protected string $writeable {
set => $value;
}
// Isso expande a visibilidade de protegida para pública, o que é aceitável.
public string $both;
}
?>
Uma propriedade abstrata em uma classe abstrata pode fornecer implementações para qualquer gancho,
mas deve ter get
ou set
declarado, mas não definido (como no exemplo acima).
Exemplo #4 Exemplo de propriedade abstrata com ganchos
<?php
abstract class A
{
// Isso fornece uma implementação de conjunto padrão (mas substituível)
// e requer que classes filhas forneçam uma implementação get.
abstract public string $foo {
get;
set {
$this->foo = $value
}
}
}
?>