Médio PHP
Fábrica estática com late static binding
Enunciado
Crie uma classe Documento com propriedades titulo e tipo. Adicione um método estático criar que recebe um array e retorna uma nova instância usando static::. Em seguida, crie a classe Relatorio que estende Documento e adiciona a propriedade periodo. Use Documento::criar e Relatorio::criar para criar objetos e exiba seus dados.
Requisitos
Documento::criardeve usarnew static(...)para permitir late static binding.Relatoriodeve estenderDocumentoe ter um construtor que aceitaperiodo.- O programa deve exibir título, tipo e, para
Relatorio, também o período.
Código inicial
<?php
class Documento
{
public function __construct(
public readonly string $titulo,
public readonly string $tipo
) {}
// TODO: implemente o método estático criar usando static::
}
class Relatorio extends Documento
{
// TODO: adicione a propriedade $periodo e o construtor
}
// TODO: use as fábricas e exiba os dados
Saída esperada
Documento: Contrato (PDF)
Relatório: Vendas (XLSX) - Período: 2025
Ver dica
No método criar, use return new static($dados['titulo'], $dados['tipo']);. Em Relatorio, o construtor deve chamar parent::__construct e definir $periodo.
Mostrar solução
<?php
class Documento
{
public function __construct(
public readonly string $titulo,
public readonly string $tipo
) {}
// Fábrica estática que respeita a classe chamada
public static function criar(array $dados): static
{
return new static($dados['titulo'], $dados['tipo']);
}
public function exibir(): string
{
return "Documento: {$this->titulo} ({$this->tipo})";
}
}
class Relatorio extends Documento
{
public function __construct(
string $titulo,
string $tipo,
public readonly string $periodo
) {
parent::__construct($titulo, $tipo);
}
public function exibir(): string
{
return "Relatório: {$this->titulo} ({$this->tipo}) - Período: {$this->periodo}";
}
}
// Usando as fábricas
$doc = Documento::criar(['titulo' => 'Contrato', 'tipo' => 'PDF']);
$rel = Relatorio::criar(['titulo' => 'Vendas', 'tipo' => 'XLSX', 'periodo' => '2025']);
echo $doc->exibir() . PHP_EOL;
echo $rel->exibir() . PHP_EOL;
Passo a passo
Documentotem duas propriedades readonly e um construtor que as define.- O método estático
criarrecebe um array e retornanew static(...). O uso destaticem vez deselfé crucial: se chamado comoRelatorio::criar,staticresolve paraRelatorio. RelatorioestendeDocumento, adiciona$periodoe chamaparent::__constructpara inicializar as propriedades herdadas.Relatoriosobrescreveexibirpara incluir o período.- Chamamos
Documento::criareRelatorio::criare exibimos os resultados.
Por que funciona
O late static binding faz com que static:: dentro de criar se refira à classe usada na chamada. Se tivéssemos usado self::, Relatorio::criar tentaria instanciar Documento, e o período não seria definido. Com static::, cada classe filha pode reutilizar a fábrica e ainda criar sua própria instância.
Erros comuns
- Usar
selfno lugar destatic:return new self(...)fariaRelatorio::criarretornar umDocumento, perdendo a propriedadeperiodo. - Esquecer de chamar
parent::__construct: as propriedadestituloetipoficariam indefinidas, causando erro. - Tentar acessar
$thisno método estático: métodos estáticos não têm$this. Use parâmetros enew static.
Outra forma de resolver
Em vez de uma fábrica estática, você pode usar um construtor normal e instanciar diretamente. A fábrica é preferível quando a criação envolve lógica extra (validação, mapeamento de array) ou quando você quer permitir que subclasses personalizem a criação.
Saída esperada
Documento: Contrato (PDF)
Relatório: Vendas (XLSX) - Período: 2025