我们在使用第三方库的时候通常使用直接加载依赖的方式来调用,比如使用日志工具--monolog。在这里我试图做这种使用第三方库的最佳实践。我们的设计考量标准就是代码的可维护、易用、性能等方面来考虑,从设计模式来说就是考虑高内聚低耦合。
如果我们只是直接加载了日志类来调用,那么我们肯定要在类里面按照这个库的规则写大量的代码,这很难看。我们不如按照适合使用习惯的方式来封装调用的方法。于是
namespace app\Library\Utils;
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
/**
* Class Logger
* @package Libraries\Utils
* @author Bardeen
*/
calss Logger
{
public static $CHANNEL_MAP = [
'baidumap' => '/log/map/',
'default' => '/log/normal/'
];
private static $channel = [];
/**
* @param $channel
* @param $message
* @param $priority
* @return $this
*/
public function log($channel_name,$message,$context,$priority){
//init
if(!isset(self::$channel[$channel_name])){
self::$channel[$channel_name] = new Logger($channel_name);
$log_path = isset(self::$CHANNEL_MAP[$channel_name])?RUNTIME_PATH . self::$CHANNEL_MAP[$channel_name] . DS:RUNTIME_PATH . self::$CHANNEL_MAP['default'];
self::$channel[$channel_name]->pushHandler(new RotatingFileHandler($log_path .$channel_name.".log", $priority));
}
$logger = self::$channel[$channel_name];
//action
$context = is_array($context)?$context:[$context];
$logger->addRecord($priority, $message, $context);
return $this;
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function errorLog($channel,$message,$context){
$priority = Logger::ERROR;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function warningLog($channel,$message,$context){
$priority = Logger::WARNING;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function infoLog($channel,$message,$context){
$priority = Logger::INFO;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function noticeLog($channel,$message,$context){
$priority = Logger::NOTICE;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function criticalLog($channel,$message,$context){
$priority = Logger::CRITICAL;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function alertLog($channel,$message,$context){
$priority = Logger::CRITICAL;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function emergancyLog($channel,$message,$context){
$priority = Logger::EMERGENCY;
return $this->log($channel,$message,$context,$priority);
}
}
好,便利类封装好了,那我们是不是就可以直接加载依赖使用?不行!其实这个东西我们可以做的更好。打印日志从业务逻辑上来说应该是类的固有属性,从高内聚的角度来说我们应该使用聚合的方式,但是我们不使用传统的聚合方式而是使用php的新特性trait。这还不够,为了性能我们使用单例享元工厂来获取原生log类。于是有以下两个文件:
LoggerTrait.php
namespace app\Library\Utils;
use Monolog\Logger;
/**
* Class LoggerTrait
* @package Libraries\Utils
* @author Bardeen
*/
trait LoggerTrait
{
/**
* @param $channel
* @param $message
* @param $priority * @return $this
*/
public function log($channel,$message,$context,$priority){
//init
$logger_flyweight = FlyweightLogger::getInstance();
$logger = $logger_flyweight::setChannel($channel,$priority);
//action
$context = is_array($context)?$context:[$context];
$logger->addRecord($priority, $message, $context);
return $this;
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function errorLog($channel,$message,$context){
$priority = Logger::ERROR;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function warningLog($channel,$message,$context){
$priority = Logger::WARNING;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function infoLog($channel,$message,$context){
$priority = Logger::INFO;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function noticeLog($channel,$message,$context){
$priority = Logger::NOTICE;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function criticalLog($channel,$message,$context){
$priority = Logger::CRITICAL;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function alertLog($channel,$message,$context){
$priority = Logger::CRITICAL;
return $this->log($channel,$message,$context,$priority);
}
/**
* @param $channel
* @param $message
* @return $this
*/
public function emergancyLog($channel,$message,$context){
$priority = Logger::EMERGENCY;
return $this->log($channel,$message,$context,$priority);
}
}
namespace app\Library\Utils;
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
class FlyweightLogger{
public static $instance = null;
public static $CHANNEL_MAP = [
'baidumap' => '/log/map/',
'default' => '/log/normal/'
];
private static $channel = [];
final private function __construct(){}
final private function __clone(){}
/**
* @return QueueAggregate
*/
final public static function getInstance(){
if(null === self::$instance){
self::$instance = new FlyweightLogger();
}
return self::$instance;
}
/**
* @param null $service_name
* @return Application|null
*/
static function getChannel($channel_name){
$return = false;
isset(self::$channel[$channel_name]) && $return = self::$channel[$channel_name];
return $return;
}
static function setChannel($channel_name,$priority){
if(!isset(self::$channel[$channel_name])){
self::$channel[$channel_name] = new Logger($channel_name);
$log_path = isset(self::$CHANNEL_MAP[$channel_name])?RUNTIME_PATH . self::$CHANNEL_MAP[$channel_name] . DS:RUNTIME_PATH . self::$CHANNEL_MAP['default'];
self::$channel[$channel_name]->pushHandler(new RotatingFileHandler($log_path .$channel_name.".log", $priority));
}
return self::$channel[$channel_name];
}
}
好了,完美。现在我们可以用use来实现这个trait。