Late Static Bindings
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 encaminhada". 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.
Limitações do self::
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:
Example #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 produzirá:
A
Uso de Late Static Bindings
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.
Example #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 produzirá:
B
Note:
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, utilizarstatic::
pode ter resultados diferentes. Outra diferença é questatic::
só pode referenciar propriedades estáticas.
Example #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 produzirá:
success! success! success! Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
Note:
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::
ouself::
irão repassar a informação do chamador.Example #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 produzirá:
A C C