Pregunta

A partir de la versión 5.3, PHP admite enlace tardío para métodos estáticos. Si bien es una característica indudablemente útil, solo hay varios casos en los que su uso es realmente necesario (por ejemplo, el patrón Active Record).

Considere estos ejemplos:

1. Constructores de conveniencia ( :: create () )

class SimpleObject
{
    public function __construct() { /* ... */ }

    public static function create()
    {
        return new static; // or: return new self;
    }
}

Si esta clase se puede extender (sin embargo, no se extiende por ninguna clase en el mismo paquete), se debe utilizar el enlace estático tardío solo para facilitar la extensión (sin tener que volver a escribir el :: create () y, lo que es más importante, sin tener que recordar hacer eso)

Nota: este modismo se usa para evitar la imposibilidad de invocar métodos en objetos recién construidos: new SimpleObject () - > doStuff () no es válido en PHP.


2. Constantes de clase

class TagMatcher
{
    const TAG_PATTERN = '/\<([a-z\-]+?)\>/i';

    private $subject;

    public function construct($subject) { $this->subject = $subject; }

    public function getAllTags()
    {
        $pattern = static::TAG_PATTERN;
        preg_match_all($pattern, $this->subject);
        return $pattern[1];
    }
}

La razón para usar static :: en este ejemplo es similar a la anterior. Se usa solo porque esta clase se puede hacer para que coincida con etiquetas de forma diferente simplemente extendiéndola y anulando la constante.


Entonces, para concluir, ¿son estos usos (y otros similares) de enlace estático tardío una exageración? ¿Hay algún impacto notable en el rendimiento? Además, ¿el uso frecuente de enlace tardío reduce el aumento del rendimiento general dado por los cachés de código de operación?

¿Fue útil?

Solución

  

Entonces, para concluir, ¿son estos usos (y otros similares) de enlace estático tardío una exageración? ¿Hay algún impacto notable en el rendimiento? Además, ¿el uso frecuente de enlace tardío reduce el aumento del rendimiento general dado por los cachés de código de operación?

La introducción del enlace estático tardío corrige una falla en el modelo de objetos de PHP. No se trata de rendimiento, se trata de semántica.

Por ejemplo, me gusta usar métodos estáticos siempre que la implementación del método no use $ this . El hecho de que un método sea estático no significa que no desee anularlo a veces. Antes de PHP 5.3, el comportamiento era que no se marcaba ningún error si anulaba un método estático, pero PHP simplemente seguía adelante y usaba silenciosamente la versión del padre. Por ejemplo, el siguiente código imprime 'A' antes de PHP 5.3. Ese es un comportamiento altamente inesperado.

El enlace estático tardío lo corrige, y ahora el mismo código imprime 'B'.

<?php
class A {
  public static function who() {
    echo __CLASS__;
  }
  public static function test() {
    static::who();
  }
}

class B extends A {
  public static function who() {
    echo __CLASS__;
  }
}

B::test();
?>

Otros consejos

los métodos estáticos (ligados temprano o tardío) crean un acoplamiento estrecho y (por lo tanto) reducen la capacidad de prueba. Puede crear programas grandes en PHP sin utilizar más de unas pocas llamadas estáticas. para mí, los métodos estáticos tardíos no son una característica.

editar para responder la pregunta de Marco Demaio, ¿cómo el método estático reduce la capacidad de prueba?

lo siento si todo esto es obvio para usted, los miembros estáticos (tanto datos como métodos) son útiles y no causan daño si se usan de manera responsable, aludía a su uso indebido frecuente.

digamos que tiene una aplicación web que usa una base de datos SQL. sus objetos comerciales pueden recuperar datos utilizando una interfaz estática o mediante polimorfismo. ya sea

class MyBusinessObject
extends...
{
  public function doThisOrThat(...)
  {
    $results = db::query('sql string...');
    ...
  }
}

o

class MyBusinessObject
extends...
{
  public function __construct(dbconn $db)
  {
    $this->db = $db;
  }
  private $db;
  public function doThisOrThat(...)
  {
    $results = $this->db->query('sql string...');
    ...
  }
}

este último es más fácil de probar (como en: quiero probar que la cadena sql construida a partir de tales y tales entradas es tal y tal) porque es más fácil crear otra implementación de dbconn de lo que es cambiar el significado de db :: . ¿por qué querrías tampoco? porque no necesita una base de datos real para probar el comportamiento de composición de sql, y de hecho es más fácil probar sin una base de datos real. Además, es más fácil desconectar al consumidor SQL si sus pruebas están relacionadas con otro aspecto del CUT (Código bajo prueba).

las pruebas siempre implican mentir al código probado sobre sus colaboradores, y abstenerse de las interfaces estáticas (el "dos puntos" o "cuadridot") significa que la mentira no necesita ser una cirugía masiva, lo cual es una ventaja, ya que cuanto más el código probado es del código de producción, menos significativos son los resultados de la prueba.

Donde encuentro la necesidad de usar el enlace estático tardío es permitir la burla de métodos estáticos para pruebas unitarias con PHPUnit. El problema que tengo es que no me gusta cambiar el código estrictamente para permitir la burla, pero puedo superarlo.

Sin embargo, para responder a su pregunta, apuesto a que, independientemente del costo de rendimiento que esto conlleve, palidecerá en comparación con la mayoría de los tiempos de ejecución del programa. En otras palabras, no hará una diferencia notable.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top