-1

I usually use Monolog for my PHP logging and debugging, but have found I end up with each of my classes instantiating there own Monolog\Logger, which is fine for a project with just one or two classes in it, but I want to share these classes across multiple projects using Composer etc. To avoid having each class use its own logger I currently use the following code which simply allows me to pass an instance of Logger if its is configured and if not then the class sets up a Null logger itself :

    /**
     * Basic Constructor
     *
     * @param Logger|Null Logging instance or Null to do no logging at all
     */
    public function __construct($logger = null)
    {
        if ($logger !== null) {
            $this->logger = $logger;
        } else {
            $this->logger = new Logger('dummy');
            $this->logger->pushHandler(new NullHandler());
        }
    }
   private function test($var1,$var2) {
        $this->logger->debug('test method called with '.$var1.' and '.$var2);
    }

Is this the best way to configure debugging for my classes or is there something that is more universal/just plain better coding practice?

I have also used a method inside my classes in the past that tests if $this->debug is not null and if so then calls Logger with the data, rather than sending everything to a null Logger but this then requires multiple methods for each log level:

 /**
     * If debug enabled, send all passed parameters to debugger
     */
    public function debug()
    {
        if (is_null($this->debug)) {
            return;
        }
        $args = func_get_args();
        $this->debug->debug(print_r($args, true));
    }

I am not using any pre built frameworks, but i would think the same problem would still occur when using my own classes with a framework.

Marl
  • 169
  • 1
  • 7
  • 2
    The problem I have with the first code is that if `$logger == null`, you go off and create a logger from a specific class with your settings. Dependency Injection is used to get away from just this scenario. I would just drop that part and either force the *user* to pass a logger or if it's null just don't log anything. – Nigel Ren Feb 11 '20 at 15:33
  • Problem I see with not logging if Logger not passed is that I then have to either use a method like the 'debug()' one above or put a test for debugging on every debug statement wouldn't I? – Marl Feb 11 '20 at 15:41
  • 2
    This is up to you. You could pass a logging class which decides (say on .env variable) what is logged and implement a message level - debug, info, warn etc. type scheme. So you would always pass a logger in for this case. – Nigel Ren Feb 11 '20 at 15:45
  • Thanks that answers my question, unless anyone else wants to chime in :) – Marl Feb 11 '20 at 15:47

1 Answers1

-1

Use a helper class in the global namespace, that has some static functions to access.

Quick fast and dirty

class Debug {
   static $logger = new Logger();
   public static function debug($input) {
      self::$logger->debug($input);
   }
   ... for other functions/wrapping you wish to do
}

Add a few helper functions

function debug($input)) {
   Debug::debug($input);
}

and then you're good to go.

You can then do debug('mystuff') or Debug::debug('mystuff');

A bit more complicated

By using a static wrapper class that interfaces via __callStatic you can pass all the instance queries you would do on logger as a static call to the debug class, without having to worry about "copying" all methods of the logger into your own Debug wrapper. When you add even a few helper functions you don't have to type so much for your debug helpers.

Another advantage is you can switch out logger types as you wish. Don't feel like monolog anymore? swap it out for something else.

A full working rudimentary example: https://ideone.com/tAKBWr

<?php
class Logger {
    public function debug($input) {
        var_dump($input);
    }
    public function log($input) {
        echo $input;
    }
}

class Debug {
    protected $logger;
    protected static $_instance = NULL;

    final private function  __construct() { 
        $this->logger = new Logger();
    }

    final private function  __clone() { }

    final public static function getInstance()
    {
        if(null !== static::$_instance){
            return static::$_instance;
        }
        static::$_instance = new static();

        return static::$_instance;
    }

    public function getLogger() 
    {
        return $this->logger;
    }

   static public function __callStatic($name, $args) 
   {
      $logger = self::getInstance()->getLogger();
      if(method_exists($logger, $name)) {

        return $logger->{$name}(...$args);
      } 
   }
}

function debug($input) 
{
    Debug::debug($input);
}

function traceLog($input) 
{
    Debug::log($input);
}


debug(['42','asdfasdf',33]);

traceLog("Moving to track 3");
Tschallacka
  • 27,901
  • 14
  • 88
  • 133