开发者

Using log4php in a static context

开发者 https://www.devze.com 2023-03-06 00:09 出处:网络
I\'m currently in the process of moving from our own proprietary logging solution to log4php. We use a lot of classes with only static methods in our project. The documentation defines the basic use c

I'm currently in the process of moving from our own proprietary logging solution to log4php.

We use a lot of classes with only static methods in our project. The documentation defines the basic use case like:

class MyClass {
   private $logger;

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

But I can't use that, cause I need $logger to be available in a static context as well. Making $logger static as well doesn't help either, because the constructor for my class is never called (as all its mem开发者_如何学Pythonbers are static).

The documentation tells me to use a static initializer for that member then. But then I would have to remember to call that for all classes I use. And that seems too error-prone.

So I came up with this:

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

But that seems like too much overhead as well. So, any suggestions?


I came up with one solution that works quite well but requires $logger to be public.

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

This I only have to define the $logger property once per class and run my initialization code once (I guess after the require_once section of the entry point of my application).

The performance impact of that code is negligible, especially since it is only run once (compared to my initial solution). This is what I measured inside a VirtualBox VM on an Intel Core2 Q9450 @2.66GHz:

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

精彩评论

暂无评论...
验证码 换一张
取 消