A partir do PHP 5.3.0, o PHP implementa um recurso chamado late static bindings que pode ser usado para referenciar a classe chamada no contexto de herança estática.
Mais precisamente, late static bindings funcionam através do armazenamento do nome da classe na última "chamada não encaminhadas". No caso de chamadas a métodos estáticos, é a classe explicitamente chamada (normalmente o nome a esquerda do operador ::); no caso de chamadas a métodos não estáticos, é o nome da classe do objeto. Uma "chamada encaminhada" é àquela estática, realizada pelos prefixos self::, parent::, static::, ou, se subindo na hierarquia de classes, forward_static_call(). A função get_called_class() pode ser utilizada para recuperar uma string com o nome da classe chamada e static:: introduz seu escopo.
Esse recurso foi chamado de "late static bindings" de uma perspectiva interna em mente. "Late binding" vem do fato que static:: não será resolvido usando a classe onde o método foi definido, mas computada utilizando informações em tempo de execução. É também chamado "static binding" pois pode ser utilizado em (mas não limitado a) chamadas de métodos estáticos.
Referências estáticas para a atual classe como self:: ou __CLASS__ são resolvidas usando a classe na qual a função pertence, como onde ele foi definido:
Exemplo #1 Uso do self::
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
O exemplo acima irá imprimir:
A
Late static bindings tenta resolver a limitação introduzindo uma palavra-chave que referencia a classe que foi inicialmente chamada em tempo de execução. Basicamente, é uma palavra-chave que permite referenciar B em test(), no exemplo anterior. Foi decidido não introduzir uma nova palavra-chave, mas usar static, já reservada.
Exemplo #2 Simples uso do static::
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // Here comes Late Static Bindings
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
O exemplo acima irá imprimir:
B
Nota:
Em contextos não estáticos a classe chamada será a classe da instância do objeto. Assim como $this-> chamará métodos privados do mesmo escopo, utilizar static:: pode ter resultados diferentes. Outra diferença é que static:: só pode referenciar propriedades estáticas.
Exemplo #3 Uso do static:: em um contexto não-estático
<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() será copiado para B, assim seu escopo ainda será A e
* e a chamada funcionará */
}
class C extends A {
private function foo() {
/* método original foi substituído, escopo agora é C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test(); //fails
?>
O exemplo acima irá imprimir:
success! success! success! Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
Nota:
As resoluções de Late static bindings terminarão quando a chamada é realizada sem retorno. Por outro lado chamadas estáticas utilizando instruções como parent:: ou self:: irão repassar a informação do chamador.
Exemplo #4 Chamadas repassadas e não repassadas
<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>O exemplo acima irá imprimir:
A C C