Abstração de Classes

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
}
}
}

?>