Desde PHP 5.3.0, PHP incorpora una nueva funcionalidad llamada enlace estático en tiempo de ejecución que permite hacer referencias a la clase en uso dentro de un contexto de herencia estática.
De forma más precisa, un enlace estático en tiempo de ejecución para funcionar almacena el nombre de clase de la última llamada que no tenga "propagación". En el caso de las llamadas a métodos estáticos, se trata de la clase a la que se llamó explícitamente (normalmente, la que precede al operador ::); en los casos de llamadas a métodos que no son estáticos, se resolvería a la clase del objeto. Una "llamada con propagación" es una llamada estática que está precedida por self::, parent::, static::, o, si seguimos la jerarquía de clases, forward_static_call(). La función get_called_class() puede utilizarse para obtener un string con el nombre de la clase que realiza la llamada, y static:: revela cuál es su alcance.
Se le ha llamado "enlace estático en tiempo de ejecución" teniendo en cuenta un punto de vista interno. "Enlace en tiempo de ejecución" viene del hecho de que static:: ya resuelve a la clase en la que se definió el método, sino que en su lugar se resolverá utilizando información en tiempo de ejecución debido a que se puede utilizar (entre otras cosas) para las llamadas de métodos estáticos, se le llamó también "enlace estático".
Las referencias estáticas que hay dentro de la clase en uso, como self:: o __CLASS__, se resuelven empleando el nombre de la clase a la que pertenece la función:
Ejemplo #1 Uso de 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();
?>
El resultado del ejemplo sería:
A
Los enlaces estáticos en tiempo de ejecución tratan de resolver estas limitaciones empleando una palabra clave que haga referencia a la clase que realizó la llamada en tiempo de ejecución. Es decir, una palabra clave que en el ejemplo anterior permita hacer referencia desde test() a B. Se decidió no crear una nueva palabra clave, por lo que en su lugar se ha utilizado la palabra reservada static.
Ejemplo #2 Uso básico de static::
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // He aquí el enlace estático en tiempo de ejecución
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
El resultado del ejemplo sería:
B
Nota:
En contextos no estáticos, la clase que realiza la llamada será la clase del objeto instanciado. Dado que $this-> tratará de invocar métodos privados en su mismo ámbito, el uso de static:: puede provocar diferents resultados. Otra diferencia es que static:: sólo puede hacer referencia a propiedades estáticas.
Ejemplo #3 Uso de static:: en un contexto no estático
<?php
class A {
private function foo() {
echo "exito!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() se copiará en B, por lo tanto su ámbito seguirá siendo A
* y la llamada tendrá éxito */
}
class C extends A {
private function foo() {
/* se reemplaza el método original; el ámbito del nuevo es ahora C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test(); //falla
?>
El resultado del ejemplo sería:
exito! exito! exito! Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
Nota:
En una llamada que se resuelva como estática, la resolución de enlaces estáticos en tiempo de ejecución se dentendrá sin propagarse. Por otra parte, las llamadas estáticas que utilicen palabras clave como parent:: o self:: sí propagarán la información.
Ejemplo #4 Llamadas que propagan y que no propagan
<?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();
?>El resultado del ejemplo sería:
A C C