我正在编写一些代码(数据库抽象层,在我的其他代码模块中使用),我想作为一个独立的模块发布,可能包含在一个项目与作曲家。我想在编写器定义中包含一些建议的模块,这些模块可以提高我的模块的性能,但这不是必需的。
我的问题是如何以一种不完全可怕的方式做到这一点。
因此,在这个特定的示例中,模块在namespace IntahwebzDB;
中声明,然后尝试包含可选模块IntahwebzLogLog
,这反过来又尝试使用可选模块Monolog
。
我现在看到的是模块代码connectionwrapper。php
namespace IntahwebzDB;
use IntahwebzLogLog;
if(trait_exists("IntahwebzLogLog") == false){
require_once("Log.php");
}
class ConnectionWrapper{
use Log;
function __construct(){
$this->initLog();
// Rest of constructor code.
$this->log->trace("ConnectionWrapper has been constructed.");
}
// Lots of other functions here.
}
?>
然后在Log.php中检查是否有可用的独白,如果有,包括它,否则定义一个真正轻量级的记录器。
<?php
namespace IntahwebzLog;
if (class_exists('MonologLogger') &&
class_exists('MonologHandlerStreamHandler')) {
require_once "MonologWrapper.php";
}
else{
class Logger{
public function debug($message, array $context = array()){
echo $message."n";
}
public function log($level, $message, array $context = array()){
echo $message."n";
}
public function info($message, array $context = array()){
echo $message."n";
}
public function notice($message, array $context = array()){
echo $message."n";
}
public function warning($message, array $context = array()){
echo $message."n";
}
public function error($message, array $context = array()){
echo $message."n";
}
public function critical($message, array $context = array()){
echo $message."n";
}
public function alert($message, array $context = array()){
echo $message."n";
}
public function emergency($message, array $context = array()){
echo $message."n";
}
}
trait Log{
var $log;
function initLog(){
$this->log = new Logger(__CLASS__);
}
}
}
如果独白可用,我们通过包含MonologWrapper.php来使用它
<?php
namespace IntahwebzLog;
use MonologLogger;
use MonologHandlerStreamHandler;
trait Log{
var $log;
function initLog(){
$this->log = new Logger(__CLASS__);
//Todo - get log handler from config file automagically.
$this->log->pushHandler(new StreamHandler(PATH_TO_ROOT.'var/log/Admin.log', Logger::WARNING));
}
}
?>
问题是:
1)它非常丑陋,并且每个建议的模块需要额外的文件。
2)它不允许人们在不重写代码的情况下切换到独白以外的其他记录器。
3)它有重复的类/trait定义,只有if语句分开,这完全混淆了我的IDE。
我知道Symfony等解决这个问题的方法是通过一个服务层。然而,我不知道如何使用这种设计模式,而不强迫依赖项包含比引入可选模块更复杂。
谁能描述一个体面的设计模式,包括可选模块,或者用其他兼容模块替换它们?或者这类东西只能在一个实际的框架中很好地定义?
依赖注入:)
例如,不用
function initLog(){
$this->log = new Logger(__CLASS__);
// ..
}
使用function setLogger(Logger $logger) {
$this->log = $logger;
// ...
}
以此类推。有太多的硬编码依赖,我不会一一提到。
class MonologLoggingConnectionWrapperWrapper extends ConnectionWrapper {
public function __construct (ConnectionWrapper $wrapper, Logger $logger) {
// ..
}
}
现在独白是必需的,当有人试图实例化这个类,然后很明显,有些东西丢失了。如果您愿意,您可以在类定义之前向文件添加一个测试,这应该(在这种情况下)抛出一个异常,或触发一个错误。
(类名源于ConnectionWrapper
不是一个真正的包装器,而是一个独立的类:包装器必须扩展被包装的类,或实现相应的接口,因此它是干净的可交换的)
值得一提的是:避免条件类或函数定义:)一个Classname,一个类(不能更多),当我试图实例化一个类时,它要么存在,要么不存在,但不是"有时"。