Construtores
O PHP permite aos desenvolvedores declararem métodos construtores para as classes.
Classes que tem um método construtor chamam o método a cada
objeto recém criado, sendo apropriado para qualquer inicialização que o
objeto necessite antes de ser utilizado.
Nota:
Construtores pais não são chamados implicitamente se a classe filha define
um construtor. Para executar o construtor da classe pai, uma chamada a
parent::__construct() dentro do construtor da classe filha
é necessária. Se a classe filha não definir um construtor, será herdado
da classe pai como um método normal (se não foi declarado
como privado).
Exemplo #1 Construtoras em herança
<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();
// In BaseClass constructor
$obj = new OtherSubClass();
?>
Diferente de outros métodos, __construct()
não precisa seguir as regras usuais de
compatibilidade de assinatura
em objetos derivados.
Construtores são métodos ordinários que são chamados durante a criação
do objeto correspondente. Eles podem definir um número arbitrários de argumentos, quais
podem ser obrigatórios, podem ter um tipo, e podem ter valores padrão. Argumentos de construtores
são informados dentro de parênteses depois do nome da classe.
Exemplo #2 Utilizando argumentos de construtor
<?php
class Point {
protected int $x;
protected int $y;
public function __construct(int $x, int $y = 0) {
$this->x = $x;
$this->y = $y;
}
}
// Passagem de ambos os argumentos.
$p1 = new Point(4, 5);
// Passar somente o argumento obrigatório, $y terá o valor padrão zero.
$p2 = new Point(4);
// Com parâmetros nomeados (a partir do PHP 8.0):
$p3 = new Point(y: 5, x: 4);
?>
Se a classe não tem construtor, ou o construtor não tem argumentos obrigatórios, o parêntesis
pode ser omitido.
Construtores em estilo antigo
Anteriormente ao PHP 8.0.0 as classes no namespace global interpretam um método com o mesmo nome
da classe como sendo um construtor válido. Essa sintaxe foi descontinuada,
e gerará um erro E_DEPRECATED
embora ainda continue funcionando como um construtor.
Se ambos o __construct() e um método homônimo da classe
estiverem definidos, __construct() que será chamado.
Em classes dentro de namespaces, ou quaisquer classes a partir do PHP 8, um método
homônimo ao nome da classe não tem um significado especial.
Sempre utilize __construct() em novos códigos.
New em inicializadores de parâmetros
A partir do PHP 8.1.0, objetos podem ser utilizados como valores padrão de parâmetros,
variáveis estáticas e constantes globais, assim como argumentos de atributos.
Novos objetos também podem ser passados na instrução define().
Nota:
Não é permitido nomes de classe não-string ou classes anônimas.
Não é permitido o espalhamento de argumentos.
Não é permitido o uso de expressões.
Exemplo #4 New em inicializações
<?php
// Permitido:
static $x = new Foo;
const C = new Foo;
function test($param = new Foo) {}
#[AnAttribute(new Foo)]
class Test {
public function __construct(
public $prop = new Foo,
) {}
}
// Não permitido, resultad em erro de compilação:
function test(
$a = new (CLASS_NAME_CONSTANT)(), // Nome dinâmico de classe
$b = new class {}, // Classe anônima
$c = new A(...[]), // Espalhamento de argumento
$d = new B($abc), // Expressão
) {}
?>
Métodos de criação estáticos
O PHP suporta apenas um único construtor por classe. Em alguns casos pode ser
desejável de permitir a um objeto ser construído de maneiras diferentes, a partir de argumentos diferentes.
O método recomendado para realizar isso é através de métodos estáticos, utilizados como empacotadores do construtor.
Exemplo #5 Utilizando métodos estáticos para construção
<?php
class Product {
private ?int $id;
private ?string $name;
private function __construct(?int $id = null, ?string $name = null) {
$this->id = $id;
$this->name = $name;
}
public static function fromBasicData(int $id, string $name): static {
$new = new static($id, $name);
return $new;
}
public static function fromJson(string $json): static {
$data = json_decode($json, true);
return new static($data['id'], $data['name']);
}
public static function fromXml(string $xml): static {
// Custom logic here.
$data = convert_xml_to_array($xml);
$new = new static();
$new->id = $data['id'];
$new->name = $data['name'];
return $new;
}
}
$p1 = Product::fromBasicData(5, 'Widget');
$p2 = Product::fromJson($some_json_string);
$p3 = Product::fromXml($some_xml_string);
O construtor pode ser private ou protected para evitar que ele seja chamado externamente.
Nesses casos apenas um construtor estático será capaz de instanciar a classe. Por eles estarem
nas mesma definição de classe, os métodos estáticos são capazes de instanciar o objeto, mesmo em
uma instância diferente. O construtor privado é opcional e pode não fazer sentido em
todos os casos.
Os três métodos estáticos a seguir demonstram as maneiras diferentes de instanciar um objeto.
fromBasicData()
obtém os exatos parâmetros que são necessários, e então cria
o objeto através da chamada do construtor e retorna o resultado
fromJson()
aceita uma string JSON, realiza algum pré-processamento para
converter os dados no formato necessário ao construtor. Só então retorna o novo objeto.
fromXml()
aceita uma string XML, pré-processa, e então cria um objeto
limpo. O construtor é chamado, mas com todos os parâmetros opcionais o método
os ignora. Por fim, os valores nas propriedades do objeto são associados antes de retornar o resultado.
Nos três casos, a palavra chave static
é convertida no nome da classe onde o código reside.
Nesse caso a classe Product
.
Destrutor
O PHP introduz um conceito de destrutor similar ao de outras
linguagens orientadas a objeto, como C++. O método destrutor será chamado
assim que todas as referências a um objeto particular forem removidas ou quando
o objeto for explicitamente destruído ou qualquer ordem na sequência de encerramento.
Exemplo #6 Exemplo de Destrutor
<?php
class MyDestructableClass
{
function __construct() {
print "In constructor\n";
}
function __destruct() {
print "Destroying " . __CLASS__ . "\n";
}
}
$obj = new MyDestructableClass();
Assim como os construtores, os destrutores da classe pai não serão chamados implicitamente pelo
PHP. Para executar o destrutor pai, deve-se fazer uma chamada
explícita a parent::__destruct() no corpo do
destrutor. Assim como construtores, uma classe filha pode herdar o destrutor
caso não implemente um.
O destrutor será chamado mesmo se o script for terminado utilizando-se
exit(). Chamar exit() em um destrutor
irá impedir que as demais rotinas de encerramento executem.
Nota:
Destrutores chamados durante o encerramento da execução do script já enviaram os cabeçalhos HTTP.
O diretório atual na fase de encerramento do script pode ser diferente
em alguns SAPIs (e.g. Apache).
Nota:
Tentar disparar uma exceção em um destrutor (chamado no término
do script), lançará um erro fatal.