PHP, как я могу сделать этот класс лучше? Предложения / обратная связь приветствуется

Лучшим предложением будет принятый ответ

Учебный класс:

<?php 

class LogInfo {
    private $first_run;         // Flag to add line break at the beginning of script execution
    private $calling_script;    // Base name of the calling script
    private $log_file;          // log file path and name
    private $log_entry;         // information to be logged
    private $log_level;         // Log severity levels: error, warning, notice, info (default)
    private $log_level_arr;     // Array of accepted log levels
    private $fh;                // File handle

    private $file_name;         // File path and name
    private $file_parts;        // Array of $file_name
    private $script_name;       // Script Name
    private $script_parts;      // Array of $script_name    

    function __construct() {
        $this->first_run        = true;
        $this->log_level_arr    = array(
                                    'info'=>'info', // default
                                    'error'=>'error',
                                    'warning'=>'warning',
                                    'notice'=>'notice',
                                    );
        $this->calling_script   = '';       
        $this->log_file         = '';
        $this->log_entry        = '';
        $this->log_level        = '';
        $this->fh               = '';
        $this->file_name        = '';
        $this->file_parts       = '';
        $this->script_name      = '';
        $this->script_parts     = '';                   
    }

    /**
     * log detailed information into calling script log files
     */
    public function logInfo($info, $level = 'info') {

        if(array_key_exists($level,$this->log_level_arr)) {
            $this->log_level = $level;
        } else {
            $this->log_level = 'undefined';
        }

        $this->calling_script = $this->getScriptBaseName();
        $this->log_file = dirname(__FILE__)."/logs/".$this->calling_script.".log";
        $this->fh = fopen($this->log_file, 'a') or die("Can't open log file: ".$this->log_file);

        if($this->first_run) {
            $this->log_entry = "\n[" . date("Y-m-d H:i:s", mktime()) . "][" .$this->log_level."]:\t".$info."\n";
        } else {
            $this->log_entry = "[" . date("Y-m-d H:i:s", mktime()) . "][" .$this->log_level."]:\t".$info."\n";
        }

        fwrite($this->fh, $this->log_entry);
        fclose($this->fh);

        $this->first_run = false;
    }

    /**
     * return the base name of the calling script
     */
    private function getScriptBaseName() {
        $this->file_name    = $_SERVER["SCRIPT_NAME"];
        $this->file_parts   = explode('/', $this->file_name);
        $this->script_name  = $this->file_parts[count($this->file_parts) - 1];
        $this->script_parts = explode('.', $this->script_name);

        return $this->script_parts[0];
    }
}

?>

Как позвонить:

$log = new LogInfo();

$txt = "This is comment";
$log->logInfo($txt." 1",'error');
$log->logInfo($txt." 2",'new');
$log->logInfo($txt." 3",'warning');
$log->logInfo($txt." 4",'notice');
$log->logInfo($txt." 5",'info');
$log->logInfo($txt." 6");

4 ответа

Решение

Я бы использовал отдельные методы для каждого уровня журнала, это было бы проще в использовании.

$ log-> error ($ msg), например.

Возможно, вы захотите, чтобы этот класс реализовал наблюдаемый интерфейс, чтобы вы могли присоединить его к другим объектам, которые затем могут использовать его для регистрации событий с использованием шаблона Observer.

interface Observer
{
    function notify($sender);
}

interface Observable
{
    function addObserver(Observer $observer);
}

class LogInfo implements Observer
{
    // ...

    public function notify($obj)
    {
        $this->logInfo($obj->getMessage());
    }

    // ...
}

class DoesSomething implements Observable
{
    // ...

    protected $observers = array();
    protected $message;

    public function addObserver(Observer $observer)
    {
        $this->observers[] = $observer;
    }

    protected function notify($message)
    {
        $this->message = $message;
        if (count($this->observers))
        {
            foreach($this->observers as $observer)
            {
                $observer->notify($this);
            }
        }
    }

    public function getMessage()
    {
        return $this->message;
    }

    public function doSomething()
    {
         // ...
         $this->notify('We did something important');
    }

    // ...
}

$obj = new DoesSomething();
$obj ->addObserver(new LogInfo());
$obj ->doSomething(); // Uses LogInfo object to log event

Как уже сказал jishi, я бы разделил уровни log-message на собственные методы. Эти log-методы были бы защищены и вызывались только через один log-метод, который общедоступен для программиста.

Также я бы добавил возможность добавлять разные типы писателей. Так что вы можете записать данные в файл, базу данных, отправить по электронной почте и так далее. Я понял бы это с инъекцией зависимости. Если вам нужен пример, о чем я думаю, просто скажите это:)

РЕДАКТИРОВАТЬ

Я сейчас дома, и, как и обещал, я дам код:

/**
 * This is an interface for the writers. All writers must implement this,
 * to ensure, that they work together with the logger-class.
 */
interface logWriter
{
    public function log($message, $type);
}

/**
 * This is your logger-class. You call this class, if you want to log something,
 * just as you do it now.
 */
class logger
{
    /** This is the most important var. All writers that shall be used, are registered
     * in this array.
     */
     protected $_writers = array();

     // Here the other vars go, that you need for your logger, like config-vars and stuff
     // ...
     // ...

     /**
      * Your constructor, probably you'll use it to configure the logger...
      */
      public function __construct($config)
      {
        //.... do stuff...
      }

      /**
       * Okay with this method you register the different writers with your logger
       */
       public function registerWriter(logWriter $writer)
       {
            // Store the write into the array with all writers.
            $this->_writers[] = $writer;
       }

       /**
        * This is your normal log-method, just as you have one now
        */
       public function log($message, $type)
       {
            // Now you iterate over all registered writers and call the log-method of the writer...
            foreach($this->_writers AS $writer)
            {
                $writer->log($message, $type);
            }
       }
}

/**
 * This is a writer that sends the log message via email to you
 */
class emailWriter implements logWriter
{
    /**
     * Implement log-method from the logWriter-interface
     */
     public function log($message, $type)
     {
        // This is simplified right now. Should be more complex in the final version
        $to = 'yourmail@yourdomain.com';
        $from = 'logmessage@yourapplication.com';
        $subject = 'Log-Message of type' . $type;
        $body = $message;
        $headers = $from . "\r\n";
        mail($to, $subject, $body, $headers);
     }
}

/**
 * This is a writer that writes the message into a log-file
 */
class fileWriter implements logWriter
{
    /**
     * Implement log-method from the logWriter-interface
     */
     public function log($message, $type)
     {
        //... Here you just do the stuff that you would do: open file, write content, close, etc...
     }
}

// ...
// Here you can develop more writers like an SMS-Writer, Jabber-IM-Writer and so on
// ...

Хорошо, теперь с помощью этого материала:

$logger = new logger();

// Register the writers with the logger
$logger->registerWriter(new emailWriter());
$logger->registerWriter(new fileWriter());

// Now log something
$logger->log('This is a test-log-message', 'info');

Поскольку мы зарегистрировали email- и fileWriter в логгере, сообщение будет записано в файл, и, как правило, вы получите электронное письмо. Если вы хотите получить только электронное письмо и не записывать сообщение в файл, только зарегистрировать emailWriter с помощью класса logger

Я часто добавляю некоторые статические функции в логгер, чтобы сделать его более легкодоступным без созданного объекта. Основываясь на предложении Цзиши различных методов для каждого уровня:

public static function info($message) {
   // do logging here
}

LogInfo::info("I can log from anywhere");

Конечно, бывают случаи, когда вы не хотите получать доступ к вашему логгеру, используя статические функции. Я обычно нахожу это легче, хотя.

Еще одно предложение - прочитать переменную конфигурации откуда-то, которая указывает уровень ведения журнала. Когда вы строите и очень любопытно, что именно происходит, вы можете повысить уровень ведения журнала из центрального местоположения (например, config.php или чего-то еще).

Измените метод основного журнала, чтобы проверить эту переменную конфигурации, прежде чем делать что-либо...

public static function info($message, $logLevel) {
    if(check_config("logLevel") >= $logLevel) {
        // do logging here
    }
}
Другие вопросы по тегам