2011-05-16 3 views
1

Je suis actuellement en train de passer de notre propre solution de journalisation propriétaire à log4php.
Nous utilisons beaucoup de classes avec seulement des méthodes statiques dans notre projet. La documentation définit le cas d'utilisation de base comme:Utilisation de log4php dans un contexte statique

class MyClass { 
    private $logger; 

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

Mais je ne peux pas l'utiliser, parce que je dois $logger être disponible dans un contexte statique aussi bien. Rendre statique aussi $logger n'aide pas non plus, car le constructeur de ma classe n'est jamais appelé (car tous ses membres sont statiques).
La documentation me dit d'utiliser un initialiseur statique pour ce membre alors. Mais alors je devrais me rappeler d'appeler cela pour toutes les classes que j'utilise. Et cela semble trop sujet aux erreurs.

Alors je suis venu avec ceci:

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

Mais cela semble trop frais généraux ainsi. Donc, des suggestions?

Répondre

0

Je suis venu avec une solution qui fonctionne très bien, mais nécessite $logger d'être 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)); 
} 

Ce que je ne dois définir la propriété $logger une fois par classe et exécuter mon code d'initialisation une fois (je suppose après la section require_once du point de ma demande d'entrée).

L'impact sur les performances de ce code est négligeable, d'autant plus qu'il n'est exécuté qu'une seule fois (par rapport à ma solution initiale). Voilà ce que je mesurais l'intérieur d'une machine virtuelle VirtualBox sur un processeur Intel Core 2 Q9450 @ 2.66GHz:

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

Votre méthode a un gros inconvénient: Dans un environnement autoloading cela ne fonctionnera pas, parce que les classes ne sont déclarées après leur première utilisation. En outre, c'est un mauvais modèle de codage pour pousser un enregistreur quelque part. Mieux vaut laisser la classe en demander une et l'injecter. – Sven

Questions connexes