views:

261

answers:

4

I am messing around with different PHP logging frameworks. I am currently trying PEAR::Log. I figured that I would use its singleton function to make sure there was only one instance of the class around.

I have a small daemon-like script I wanted to add logging to because it was probably the simplest script in the system to test. This script has several functions. I will probably want to log things inside the functions.

The question I have is how do I best manage this singleton?

To me calling this:

&Log::singleton($handler, $name, $ident, $conf, $maxLevel);

in every function doesn't seem ideal especially since I already specified all of the options in the initial call. Pear::Log serializes this info, but from what it looks like you still have to provide all of those variables to get the instance.

Another alternative is passing the instance into every function. Again, seems like it's less than ideal.

I suppose you could make the instance a 'global' as well.

What do you in this situation? Are there better solutions?

+1  A: 

I don't know much about PEAR::Log, but why not create another singleton that wraps/simplifies logging.

class Logger {

    private static $log;

    private function __construct() { }

    public static function init(Log $log) {
        self::$log = $log;
    }

    public static function get() {
        return self::$log;
    }

}

Once you initialize Logger with Log instance you can access it via Logger::get. Since dereference is possible in PHP you can then do

Logger::get()->doSomething($foo, $bar);
Michał Rudnicki
+1  A: 

Just use a global instance. Somewhere you must have a file that all other files must include. Just instantiate it there. If you have something against global variables you probably shouldn't be programming in PHP.

jmucchiello
A singleton can be namespace specific (that is "prefixed class" pre 5.3), which a global variable can not afaik. Its always nice when you include a library which use a global variable it wont work without ...
OIS
If he's writing a library, being cautious is good. But for my own non-library code I prefer readability. $LOGGER->foo() is much nicer than Logger::get()->foo(). With my version, you can disable the logger with a small class: class NoLogger { public function __get() {} public function __call() {} };
jmucchiello
+2  A: 

Better yet, if your end goal is to just be able to blindly call

Logger::Write("Something happened");

wherever you need it, you can take Michal's solution one step further with

class Logger {

private static $log = null;

public static function init(Log $log) {
    self::$log = $log;
}

public static function Write(String $str) {
    if($log == null)
        init(Log::singleton(...));

    $this->log->Write($str);
}

}

That way, your log will be initialized once, the first time it's used.

Coderer
A: 

Another alternative is passing the instance into every function. Again, seems like its less than ideal.

Basically you have the choice of passing dependencies per function, per object instance or in one of the global scopes. I find that using the object instance scope usually hits a good balance of flexibility. Generally, you should try to limit the scope of variables as much as possible, so if it makes sense, by all means pass through function parameters.

troelskn