Использование log4php в статическом контексте - PullRequest
1 голос
/ 16 мая 2011

В настоящее время я нахожусь в процессе перехода от нашего собственного проприетарного решения для ведения журнала к log4php.
В нашем проекте мы используем много классов, использующих только статические методы.Документация определяет базовый вариант использования, например:

class MyClass {
   private $logger;

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

Но я не могу это использовать, потому что мне нужно, чтобы $logger также был доступен в статическом контексте.Кроме того, создание $logger статического также не помогает, потому что конструктор для моего класса никогда не вызывается (так как все его члены статические).
В документации говорится, что я должен использовать статический инициализатор для этого члена.Но тогда я должен был бы не забыть назвать это для всех классов, которые я использую.И это кажется слишком подверженным ошибкам.

Так что я придумал следующее:

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();

Но это тоже слишком много накладных расходов.Итак, есть предложения?

1 Ответ

0 голосов
/ 16 мая 2011

Я придумал одно решение, которое работает достаточно хорошо, но для публичного доступа требуется $logger.

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 ) );
}

Для этого мне нужно только определить свойство $logger для каждого класса и запустить код инициализацииодин раз (я думаю, после раздела require_once точки входа моего приложения).

Влияние этого кода на производительность незначительно, тем более что он запускается только один раз (по сравнению с моим первоначальным решением).Это то, что я измерил в виртуальной машине VirtualBox на Intel Core2 Q9450 с частотой 2,66 ГГц:

10000 iterations for 157 classes completed in 2.6794s. Average per iteration: 0.00026794s
...