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