Menu
Coddy logo textTech

Vinculação Estática Tardia

Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy. Lição 36 de 91.

Quando você usa self:: em uma classe pai, ele sempre se refere à classe onde está escrito, não à classe que está sendo realmente usada. Isso pode causar um comportamento inesperado na herança. A resolução estática tardia resolve esse problema usando a palavra-chave static::.

Considere este exemplo em que self:: não funciona como esperado:

<?php
class ParentClass {
    public static function create() {
        return new self();
    }
    
    public static function getClassName() {
        return self::class;
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();

Saída:

ParentClass
ParentClass

Embora tenhamos chamado ChildClass::create(), obtivemos um objeto ParentClass porque self:: é resolvido em tempo de compilação. Agora vamos usar static:::

<?php
class ParentClass {
    public static function create() {
        return new static();
    }
    
    public static function getClassName() {
        return static::class;
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();

Saída:

ChildClass
ChildClass

Com static::, o PHP espera até o tempo de execução para determinar qual classe usar. Isso é chamado de ligação "tardia" porque a decisão é adiada. É essencial para métodos de fábrica e qualquer método estático que deva respeitar a herança.

Ponto principal: Use static:: em vez de self:: quando quiser que as classes filhas herdem e personalizem corretamente o comportamento estático.

challenge icon

Desafio

Fácil

Vamos criar um sistema de registro de modelos que demonstra o poder do late static binding. Você criará uma classe base Model com um método de fábrica que as classes filhas podem herdar e, graças a static::, cada classe filha criará corretamente instâncias de si mesma em vez da classe pai.

Você organizará seu código em quatro arquivos:

  • Model.php: Crie uma classe base Model com uma propriedade estática protegida $tableName definida como "models". Adicione um método estático create() que use new static() para retornar uma nova instância de qualquer classe que o tenha chamado. Adicione outro método estático getTable() que retorne static::$tableName. Por fim, adicione um método describe() que retorne "[ClassName] from table [tableName]" usando static::class e static::$tableName.
  • User.php: Crie uma classe User que estenda Model. Inclua o arquivo pai. Substitua a propriedade estática $tableName por "users". A classe herda todos os métodos de Model sem nenhuma alteração.
  • Product.php: Crie uma classe Product que estenda Model. Inclua o arquivo pai. Substitua a propriedade estática $tableName por "products". Novamente, a classe herda todos os métodos da classe pai.
  • main.php: Inclua os arquivos User e Product. Use o método de fábrica herdado create() para criar instâncias de User e Product. Para cada instância, chame describe() e imprima o resultado em sua própria linha. Em seguida, imprima o nome da tabela de cada classe usando User::getTable() e Product::getTable(), cada um em sua própria linha.

A mágica é que os métodos create() e getTable() são definidos somente na classe pai Model, mas funcionam corretamente com as classes filhas porque static:: adia a vinculação até o tempo de execução. Quando você chama User::create(), o PHP cria uma instância de User, não uma instância de Model, porque static:: se refere à classe que foi realmente chamada.

Sua saída deve mostrar quatro linhas: a descrição da instância de User, a descrição da instância de Product, o nome da tabela de User e o nome da tabela de Product.

Experimente você mesmo

<?php

require_once 'User.php';
require_once 'Product.php';

// TODO: Use o método de fábrica create() herdado para criar uma instância de User

// TODO: Use o método de fábrica create() herdado para criar uma instância de Product

// TODO: Chame describe() na instância de User e imprima o resultado

// TODO: Chame describe() na instância de Product e imprima o resultado

// TODO: Imprima User::getTable()

// TODO: Imprima Product::getTable()

?>
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de PHP online