Construtores e destrutores
Esta aula aborda construtores e destrutores em PHP, incluindo o método __construct, a promoção de propriedades introduzida no PHP 8, o método __destruct e boas práticas de inicialização. Você aprenderá como criar objetos com estado inicial e liberar recursos automaticamente.
Construtores e destrutores são métodos especiais em PHP que permitem controlar o ciclo de vida dos objetos. O construtor é chamado automaticamente quando um objeto é instanciado, e o destrutor é chamado quando o objeto é destruído ou o script termina. Nesta aula, exploraremos o método __construct, a promoção de propriedades (PHP 8+), o método __destruct e boas práticas de inicialização.
Esses recursos são fundamentais para escrever código orientado a objetos limpo e eficiente, garantindo que os objetos sejam configurados corretamente e que recursos como conexões de banco de dados ou arquivos sejam liberados adequadamente.
__construct
O método __construct é o construtor de uma classe. Ele é executado automaticamente quando um novo objeto é criado com a palavra-chave new. Sua principal finalidade é inicializar as propriedades do objeto ou executar ações necessárias para o funcionamento do objeto.
O construtor pode receber parâmetros, permitindo que valores sejam passados no momento da instanciação. Diferente de outras linguagens, o PHP não permite múltiplos construtores (sobrecarga), mas você pode usar valores padrão ou argumentos variáveis para simular comportamentos diferentes.
<?php
class Usuario {
public string $nome;
public string $email;
public function __construct(string $nome, string $email) {
$this->nome = $nome;
$this->email = $email;
echo "Usuário criado: $nome\n";
}
}
$usuario = new Usuario("João", "joao@email.com");
// Saída: Usuário criado: João
?>
No exemplo acima, o construtor recebe dois parâmetros e os atribui às propriedades do objeto. Note que o construtor pode executar qualquer código, como validações, logging ou inicialização de dependências.
Promoção de propriedades (PHP 8)
Desde o PHP 8, é possível usar a promoção de propriedades no construtor. Isso permite declarar e inicializar propriedades diretamente nos parâmetros do construtor, reduzindo a verbosidade do código. A sintaxe combina a declaração da propriedade com a atribuição.
Para usar a promoção, basta adicionar um modificador de visibilidade (public, protected ou private) antes do parâmetro. O PHP automaticamente cria a propriedade e atribui o valor recebido. Isso elimina a necessidade de declarar a propriedade separadamente e escrever a atribuição manual.
<?php
class Usuario {
// Promoção de propriedades: declaração e atribuição em uma linha
public function __construct(
public string $nome,
public string $email
) {
echo "Usuário criado: $nome\n";
}
}
$usuario = new Usuario("Maria", "maria@email.com");
echo $usuario->nome; // Maria
?>
Além de reduzir código, a promoção de propriedades torna a intenção mais clara. Você pode misturar parâmetros promovidos com parâmetros comuns (sem visibilidade), mas os promovidos devem vir antes dos não promovidos. Também é possível definir valores padrão e tipos complexos.
__destruct
O método __destruct é o destrutor de uma classe. Ele é chamado automaticamente quando o objeto é destruído, seja porque o script terminou, seja porque não há mais referências ao objeto (coleta de lixo). O destrutor não aceita parâmetros e não retorna valor.
O destrutor é útil para liberar recursos externos, como fechar conexões de banco de dados, arquivos abertos ou liberar memória alocada. É importante notar que o destrutor não é chamado explicitamente pelo programador; o PHP gerencia isso automaticamente.
<?php
class Arquivo {
private $handle;
public function __construct(string $caminho) {
$this->handle = fopen($caminho, "w");
echo "Arquivo aberto.\n";
}
public function escrever(string $texto) {
fwrite($this->handle, $texto);
}
public function __destruct() {
if ($this->handle) {
fclose($this->handle);
echo "Arquivo fechado.\n";
}
}
}
$arquivo = new Arquivo("teste.txt");
$arquivo->escrever("Olá, mundo!");
// Quando o script terminar ou o objeto for destruído, o destrutor será chamado
?>
No exemplo, o destrutor garante que o arquivo seja fechado, mesmo que o programador esqueça de fazê-lo. Isso evita vazamento de recursos.
Inicialização
Além do construtor, existem outras formas de inicializar objetos em PHP. Uma delas é o método __init (não é um método mágico padrão), mas a abordagem mais comum é usar o construtor. No entanto, em alguns padrões de projeto, como Factory ou Singleton, a inicialização pode ser feita de maneira diferente.
Outra técnica é usar um método estático para criar e retornar uma instância, permitindo validações ou configurações antes da construção. Isso é conhecido como “named constructor” ou “static factory method”.
<?php
class Usuario {
public function __construct(
public string $nome,
public string $email
) {}
// Factory method
public static function criarComEmail(string $nome, string $email): self {
// validação do email
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("Email inválido");
}
return new self($nome, $email);
}
}
$usuario = Usuario::criarComEmail("Ana", "ana@email.com");
?>
Além disso, o PHP permite inicializar propriedades com valores padrão na declaração. Isso é útil quando o construtor não recebe todos os parâmetros. Por exemplo:
<?php
class Config {
public string $host = "localhost";
public int $porta = 3306;
public function __construct(string $host = null, int $porta = null) {
if ($host !== null) {
$this->host = $host;
}
if ($porta !== null) {
$this->porta = $porta;
}
}
}
?>
Boas práticas
Ao usar construtores, evite realizar operações pesadas ou com efeitos colaterais que possam falhar. Se a inicialização pode lançar exceções, documente isso. Prefira a promoção de propriedades quando possível, pois reduz boilerplate. Use destrutores apenas para liberar recursos; não confie neles para lógica de negócios, pois seu tempo de execução é imprevisível. Considere usar padrões como Factory para construções complexas.
Referências
- PHP Manual: Construtores e Destrutores
- PHP Manual: Promoção de Propriedades no Construtor
- PHP Manual: Destrutor
- PHP Manual: Classes e Objetos
- PHP Manual: Padrões de Projeto
Exercícios
Crie uma classe
Carrocom propriedadesmarca,modeloeano. Utilize um construtor para inicializar essas propriedades. Instancie um objeto e exiba os valores.✓ Resposta:<?php class Carro { public string $marca; public string $modelo; public int $ano; public function __construct(string $marca, string $modelo, int $ano) { $this->marca = $marca; $this->modelo = $modelo; $this->ano = $ano; } } $carro = new Carro("Toyota", "Corolla", 2020); echo "{$carro->marca} {$carro->modelo} ({$carro->ano})"; ?>Refatore a classe
Carrodo exercício anterior usando promoção de propriedades do PHP 8. Mantenha o mesmo comportamento.✓ Resposta:<?php class Carro { public function __construct( public string $marca, public string $modelo, public int $ano ) {} } $carro = new Carro("Honda", "Civic", 2021); echo "{$carro->marca} {$carro->modelo} ({$carro->ano})"; ?>Crie uma classe
Loggerque abre um arquivo para escrita no construtor e o fecha no destrutor. O construtor deve receber o nome do arquivo. Implemente um métodolog(string $mensagem)que escreve a mensagem no arquivo.✓ Resposta:<?php class Logger { private $handle; public function __construct(string $arquivo) { $this->handle = fopen($arquivo, "a"); } public function log(string $mensagem): void { fwrite($this->handle, date("Y-m-d H:i:s") . " - $mensagem\n"); } public function __destruct() { if ($this->handle) { fclose($this->handle); } } } $logger = new Logger("app.log"); $logger->log("Iniciando aplicação"); // O arquivo será fechado automaticamente ?>Explique por que o destrutor não deve ser usado para lógica de negócios crítica. Dê um exemplo de situação em que isso poderia causar problemas.
✓ Resposta:O destrutor é chamado em momentos imprevisíveis: quando o objeto sai do escopo, quando o script termina ou durante a coleta de lixo. Se você colocar lógica de negócios no destrutor, como enviar um email ou atualizar um banco de dados, pode ocorrer que essa lógica seja executada em um estado inconsistente (por exemplo, após uma exceção não tratada) ou nunca seja executada se o objeto for mantido em memória. Além disso, exceções lançadas no destrutor não podem ser capturadas adequadamente. Um exemplo problemático: uma classe que envia um email de confirmação no destrutor; se o script falhar antes, o email pode ser enviado indevidamente ou não ser enviado.
Crie uma classe
Configuracaoque utiliza um método estáticocarregar(string $arquivo)como factory. O método deve ler um arquivo JSON e retornar uma instância com as propriedades preenchidas. Use promoção de propriedades no construtor.✓ Resposta:<?php class Configuracao { public function __construct( public string $host, public string $usuario, public string $senha ) {} public static function carregar(string $arquivo): self { $dados = json_decode(file_get_contents($arquivo), true); return new self( $dados['host'], $dados['usuario'], $dados['senha'] ); } } // Supondo config.json: {"host":"localhost","usuario":"root","senha":"123"} $config = Configuracao::carregar("config.json"); echo $config->host; // localhost ?>