1

我正在编写一些代码(数据库抽象层,用于我的其他代码模块),我想将其作为独立模块发布,可以包含在 composer 的项目中。我想在作曲家定义中包含一些可以提高我的模块性能的建议模块,但这不是必需的。

我遇到的问题是如何以一种完全可怕的方式做到这一点。

因此,在这个特定的示例中,模块被声明,namespace Intahwebz\DB;然后Intahwebz\Log\Log尝试包含可选模块,然后尝试使用可选模块Monolog

到目前为止我所拥有的是模块代码 ConnectionWrapper.php

namespace Intahwebz\DB;

use Intahwebz\Log\Log;


if(trait_exists("Intahwebz\Log\Log") == 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 中检查 Monolog 是否可用,如果可用,则包含它,否则定义一个真正轻量级的记录器。

<?php

namespace Intahwebz\Log;

if (class_exists('Monolog\Logger') &&
    class_exists('Monolog\Handler\StreamHandler')) {

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__);
        }
    }
}

如果 Monolog 可用,我们通过包含 MonologWrapper.php 来使用它

<?php

namespace Intahwebz\Log;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

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) 它具有重复的类/特征定义,仅由 if 语句分隔,这完全混淆了我的 IDE。

我知道 Symfony 等人解决这个问题的方法是拥有一个服务层。但是,如果不强制依赖包含比引入可选模块应该复杂得多,我看不出如何使用该设计模式。

谁能描述一个体面的设计模式来包含可选模块,或者用其他兼容模块替换它们?或者这是只能在实际框架中很好地定义的事物类型?

4

1 回答 1

4

依赖注入:)

例如,而不是

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不是真正的包装器,而是它自己的一个类:包装器必须扩展被包装的类,或者实现相应的接口,因此它是完全可交换的)

值得一提:避免条件类或函数定义:)一个类名,一个类(不是更多),当我尝试实例化一个类时,它要么存在,要么不存在,但不是“有时”。

于 2013-03-03T02:25:47.827 回答