Использование log4php в статическом контексте
В настоящее время я нахожусь в процессе перехода от нашего собственного решения для ведения журналов на 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 ответ
Я придумал одно решение, которое работает довольно хорошо, но требует $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