Nuevo yo versus nueva estática

513

Estoy convirtiendo una biblioteca PHP 5.3 para que funcione en PHP 5.2. Lo principal que se interpone en mi camino es el uso de enlaces estáticos tardíos como return new static($options);, si convierto esto return new self($options), ¿obtendré los mismos resultados?

¿Cuál es la diferencia entre new selfy new static?

Miguel
fuente

Respuestas:

890

¿obtendré los mismos resultados?

Realmente no. Sin embargo, no conozco una solución alternativa para PHP 5.2.

¿Cuál es la diferencia entre new selfy new static?

selfse refiere a la misma clase en la que la newpalabra clave se escribe realmente.

static, en los enlaces estáticos tardíos de PHP 5.3, se refiere a cualquier clase en la jerarquía en la que invocó el método.

En el siguiente ejemplo, Bhereda ambos métodos de A. La selfinvocación está vinculada Aporque se define en Ala implementación del primer método, mientras que staticestá vinculada a la clase llamada (también ver get_called_class()).

class A {
    public static function get_self() {
        return new self();
    }

    public static function get_static() {
        return new static();
    }
}

class B extends A {}

echo get_class(B::get_self());  // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A
BoltClock
fuente
tiene sentido. Creo que la mejor opción es pasar el nombre de la clase a la función que utiliza el enlace estático tardío y luego devolver el nuevo $ className ($ opciones);
Mike
12
No tiene que "pasar" el nombre de la clase, siempre puede hacerlo get_called_class(), que es efectivamente el mismo __CLASS__pero compatible con LSB.
sombra
77
get_called_class no existe en <PHP5.3. Por lo tanto, si desea obtener el nombre de clase del objeto instanciado en PHP5.2 Esta función no ayuda al intentar convertir una biblioteca de PHP 5.3 a PHP 5.2
txwikinger
2
La función llamada como self :: theFunction () se comporta como "Ejecutaré en el contexto de la clase a la que pertenezco físicamente". y la función llamada como static :: theFunction () se comporta como "Ejecutaré en el contexto de la clase que ha sido llamada por el mundo exterior". (Suponiendo el escenario de herencia). Gracias
Shubhranshu
2
En mi cabeza, simplemente tomo lo que sea intuitivo y lo opuesto. Pensarías en base a la denominación, selfregresaría a sí mismo y staticdevolvería algo que no puede ser anulado ... Pero mira y es todo lo contrario. Nunca dejo de sentirme impresionado por los nombres, las convenciones y el estilo general de PHP. -_-
ahnbizcad
23

Si el método de este código no es estático, puede obtener una solución en 5.2 utilizando get_class($this).

class A {
    public function create1() {
        $class = get_class($this);
        return new $class();
    }
    public function create2() {
        return new static();
    }
}

class B extends A {

}

$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));

Los resultados:

string(1) "B"
string(1) "B"
Marius Balčytis
fuente
17
Si el método no es estático, los enlaces estáticos tardíos se vuelven totalmente irrelevantes.
BoltClock
1
Por ejemplo, podría usarlo en el método de "copia", donde el objeto se copia sin usar clone, pero simplemente recreando y configurando las propiedades. $copy = new static(); $copy->set($this->get()); return $copy;
Marius Balčytis
99
@BoltClock ¿Seguramente no? Si está llamando a un método estático anulado desde un método de instancia de una subclase, entonces su elección self::o static::afectará si se utiliza la versión de la clase base o la subclase de ese método estático. En ausencia de alguna razón para pensar que tal situación ocurra inherentemente indica mala práctica (y no veo ninguna razón por la cual esto sea así), la elección entre self::y static::es tan relevante dentro de los métodos no estáticos como lo es en métodos estáticos ¿He entendido mal su comentario, o uno de nosotros simplemente está equivocado?
Mark Amery
44
@ Mark Amery: Hmm, no pensé en eso. Estás absolutamente en lo correcto. Supuse que no se llamarían métodos estáticos en el método de instancia en cuestión, pero según su ejemplo, puedo ver cómo sería una suposición muy ingenua.
BoltClock
Enlaces estáticos tardíos doc => php.net/manual/en/language.oop5.late-static-bindings.php
DevWL
7

Además de las respuestas de otros:

static :: se calculará utilizando información de tiempo de ejecución.

Eso significa que no puede usar static::en una propiedad de clase porque los valores de las propiedades:

Debe poder evaluarse en tiempo de compilación y no debe depender de la información de tiempo de ejecución.

class Foo {
    public $name = static::class;

}

$Foo = new Foo;
echo $Foo->name; // Fatal error

Utilizando self::

class Foo {
    public $name = self::class;

}
$Foo = new Foo;
echo $Foo->name; // Foo

Tenga en cuenta que el comentario de error fatal en el código que hice no indica dónde ocurrió el error, el error ocurrió antes de que el objeto se instanciara como @Grapestain mencionado en los comentarios

Lluvia
fuente
44
Tenga en cuenta que el error se produce en la línea 2 public $name = static::class;, no en la línea 7, como sugiere el ejemplo. El error dice: "la clase static :: no se puede usar para la resolución del nombre de la clase en tiempo de compilación", lo que indica que el problema no es donde intenta acceder al campo $ name, sino mucho antes, en la compilación de la clase PHP. La línea 7 (o 6) no se alcanzará en el primer ejemplo.
sbnc.eu
@Grapestain El comentario que hice en el ejemplo fue mostrar el resultado final y no indicar dónde ocurrió realmente el error. Pero de todos modos, gracias por señalar eso.
Lluvia
Bien, no quise criticar, solo clarifiqué lo que me confundió primero con la esperanza de que pueda ayudar a otros. Ejemplo útil de todos modos!
sbnc.eu