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) コードを書き直さずに monolog 以外の別のロガーに切り替えることはできません。

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) {
        // ..
    }
}

現在、Monolog が必要になるのは、誰かがこのクラスをインスタンス化しようとしたときに、何かが欠けていることが明らかな場合だけです。必要に応じて、クラス定義の前にファイルにテストを追加できます。これにより、(この場合) 例外がスローされるか、エラーがトリガーされます。

(クラス名は、実際にConnectionWrapperはラッパーではなく、それ自体がクラスであるという事実に由来します。ラッパーは、ラップされたクラスを拡張するか、対応するインターフェースを実装する必要があるため、きれいに交換できます)

言及する価値があります: 条件付きのクラス定義または関数定義を避けてください:) 1 つのクラス名、1 つのクラス (それ以上ではない)、およびクラスをインスタンス化しようとすると、存在するかどうかのどちらかですが、「時々」ではありません。

于 2013-03-03T02:25:47.827 に答える