2011-05-16 22 views
6

Recientemente me han dicho que la clase/métodos estáticos son malvados.¿Puedo usar clases estáticas para mi registrador?

Tomemos por ejemplo mi registrador de clase:

class Logger{ 
    private static $logs = array(); 
    public static function add($msg){ 
     self::$logs[]=$msg; 
    } 

    public static function echo(){ 
     print_r(self::$logs); 
    } 
} 

puedo usar cuando quiera en mi appliaction así:

Logger::add('My log 1'); 

Pero la lectura de este desarrolladores:

Esa clase de registrador no parece tan buena.

Entonces: ¿Puedo usarlo estáticamente o debo evitarlo a toda costa?

Respuesta

10

Las clases de registro son la excepción.

Dado que rara vez contienen mucha lógica, no tiene las mismas inquietudes de prueba.

El registro es un ejemplo perfecto de un BUEN lugar para usar clases estáticas.

Piense en sus alternativas:

  • una instancia global de un objeto de registro?
  • ¿Objeto de registro singleton?
  • ¿Pasar el objeto de registro a cada método/clase (a través de un constructor)?

Lo anterior es mucho peor que usar static para el registro.

+0

Él escribe en su pregunta '¿Puedo usar cuando quiera en mi appliaction como esto'. ¿Cuál es la diferencia de usar un Logger :: log() estático con una instancia global? Si llama a Logger :: log() en métodos aleatorios, sus dependencias no son claras + las pruebas se vuelven difíciles (no puede burlarse de su registrador, por lo tanto, dependen de su funcionamiento). – koen

0

El único problema con las clases estáticas es que son difíciles de cambiar. Así que está bien aquí ya que tu clase no hace mucho.

1

Si bien no hay nada de malo en este enfoque, recientemente pasé de un enfoque de clase de registro estático al log4php en uno de mis propios proyectos.

log4php usa una instancia separada de una clase de registro para cada clase en su proyecto. Al observar ese marco de registro, los beneficios se vuelven obvios.

Los mensajes registrados siempre tienen un contexto (la clase a través de la cual se registró el mensaje). Eso permite un filtrado fácil (y hace que el registro sea un poco más útil).

+0

bastante bonito +1 (aunque el contexto se puede agregar fácilmente a mi clase obteniendo la información de la llamada a debug_backtrace) – dynamic

4

Evítalo. He visto bastantes publicaciones tuyas que ahora luchan con el tema y personas que te dan un mal consejo. Voy a repetir lo que dije en algunas de mis respuestas/comentarios.

La forma en que usa estática en su clase de registrador es usarlo como un punto de acceso global. Cuando necesite iniciar sesión, llame a Logger :: log().

1) No podrá ver, según su definición de clase, que depende de la clase Logger. El cambio en el código se convierte así en una aventura: "Espero no romper una dependencia oculta cuando cambie este pequeño ... ¡OOPS!".

2) ES MÁS difícil de probar. No se puede probar de manera realista una clase que envía un mensaje al registrador con Logger :: log(). Cuando falla una prueba, ¿cómo sabrá que no es porque el Registrador falla? Sabría si podría reemplazarlo con un simulacro, pero en su caso no es burlable.

Una alternativa para explorar:

utilizar el patrón de observador y crea el registrador de observador, a las clases que necesitan el registro puede ser observables. Envían mensajes como $ this-> observers-> nofify ('prueba exitosa').

También podría usar alguna otra forma de eventos o inyección de dependencia (automática o manual). Pero, por favor, no llame a Logger :: log() en un método.

+1

antes que nada gracias. En segundo lugar, dice que los métodos estáticos son más difíciles de probar. ¿Lo dices incluso si en php 5.3 puedes usar 'static ::'? Referencia: http://stackoverflow.com/questions/6035822/static-methods-are-they-still-bad-considering-php-5-3-late-static-binding. Esperando respuesta para preguntar más – dynamic

+1

@ yes123 Puede probar métodos estáticos del objeto bajo prueba. Pero no puede probar un método que tenga un código que llame a un método estático de otra clase. El método estático en sí es comprobable, las llamadas a ese método hacen que el código de llamada sea difícil de probar. – koen

1

Todavía creo que el registro es un enfoque válido para utilizar una clase estática. La frase a menudo declarada de que no es verificable tampoco es verdad si lo haces bien. Quiero implementar esto pero no encontré el tiempo, sin embargo, pensé en algo como lo siguiente.

class Logger { 

    protected static $handlerSet = []; 

    // Pure static class {{{ 
     private function __construct() {} 
     private function __clone() {} 
     private function __sleep() {} 
     private function __wakeup() {} 
    // }}} 

    public static function critical($message, array $context = []) {} 

    // You know the PSR drill... 

    private static function log($level, $message, array $context) { 
     foreach ($this->handlerSet as $handler) { 
      $handler->handle($level, $message, $context); 
     } 
    } 

} 

Por supuesto que no queremos exponer a la gestión de los manipuladores a todas las clases, por lo tanto, se utiliza una clase de niño que tiene acceso al conjunto manipulador protegida.

final class LoggingManager extends Logger { 

    public static function addHandler(Handler $handler, $name, $level) { 
     static::$handlerSet[$name] = $handler; 
    } 

    public static function removeHandler($name) { 
     if (isset(static::$handlerSet[$name])) { 
      unset(static::$handlerSet[$name]); 
     } 
    } 

    public static function resetHandlers() { 
     static::$handlerSet = []; 
    } 

    // Other useful stuff... 

} 

La prueba es ahora bastante fácil, si realmente desea probar algo así como la explotación forestal (podría ser que tiene algún retorno de la inversión para usted, no sé).

class SomeTest extends YourFrameworksTestCase { 

    public function testThatSomethingLogsSomething() { 
     try { 
      $handler = new TestLogHandler(); 
      LoggingManager::registerHandler($handler, 'test', 'debug'); 
      // Test something. 
      $this->assertLogRecordExists($handler, '[debug] StackOverflow'); 
     } 
     finally { 
      LoggingManager::resetHandlers(); 
     } 
    } 

} 

También sería posible crear un caso de prueba más sofisticados para extender que implementa toda la afirmación de entrada de registro para usted. Este enfoque es bastante fácil y una clase en su sistema no debería importar si un controlador está registrado o no, ni qué hace con los mensajes registrados. Cosas así se manejan en su aplicación y solo allí. Las ventajas son obvias:

  • Acceso global al administrador de registro y registro.
  • Prueba fácil, comparable a la inyección de dependencia.
  • No hay necesidad de codificar las soluciones DIC.
  • Instancia de registrador único, siempre.
  • ...
Cuestiones relacionadas