Pregunta

Actualmente estoy en el proceso de pasar de nuestra propia solución de registro patentada a log4php.
Usamos muchas clases con solo métodos estáticos en nuestro proyecto.La documentación define el caso de uso básico como:

class MyClass {
   private $logger;

   public function __construct() {
       $this->logger = Logger::getLogger(__CLASS__);
       $this->logger->debug('currently in constructor');
   }
} 

Pero no puedo usar eso, porque necesito $logger estar disponible también en un contexto estático.Haciendo $logger static tampoco ayuda, porque nunca se llama al constructor de mi clase (ya que todos sus miembros son estáticos).
La documentación me dice que use un inicializador estático para ese miembro en ese momento.Pero luego tendría que recordar llamar así para todas las clases que uso.Y eso parece demasiado propenso a errores.

Entonces se me ocurrió esto:

class Foo {
  private static $logger = null;
  private static function logger() {
    if( null == self::$logger ) self::$logger = Logger::getLogger( __CLASS__ );
    return self::$logger;
  }

  public static function bar() {
    self::logger()->debug( "test" );
  }
}

Foo::bar();

Pero eso también parece demasiado.Entonces, ¿alguna sugerencia?

¿Fue útil?

Solución

Se me ocurrió una solución que funciona bastante bien pero requiere $logger ser público.

class Foo {
  public static $logger = null;

  public static function bar() {
    self::$logger->debug( "test" );
  }
}

$loggerName = "logger";
// Iterate over all declared classes
$classes = get_declared_classes();
foreach( $classes as $class ) {
  $reflection = new ReflectionClass( $class );

  // If the class is internally defined by PHP or has no property called "logger", skip it.
  if( $reflection->isInternal() || !$reflection->hasProperty( $loggerName ) ) continue;

  // Get information regarding the "logger" property of this class.
  $property = new ReflectionProperty( $class, $loggerName );

  // If the "logger" property is not static or not public, then it is not the one we are interested in. Skip this class.
  if( !$property->isStatic() || !$property->isPublic() ) continue;

  // Initialize the logger for this class.
  $reflection->setStaticPropertyValue( $loggerName, Logger::getLogger( $class ) );
}

Esto solo me queda definir el $logger propiedad una vez por clase y ejecutar mi código de inicialización una vez (supongo que después del require_once sección del punto de entrada de mi solicitud).

El impacto en el rendimiento de ese código es insignificante, especialmente porque solo se ejecuta una vez (en comparación con mi solución inicial).Esto es lo que medí dentro de una máquina virtual VirtualBox en un Intel Core2 Q9450 a 2,66 GHz:

10000 iterations for 157 classes completed in 2.6794s. Average per iteration: 0.00026794s
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top