1

私の Web サイトの多くで、"Logger" と呼ばれる自家製の PHP クラスを使用しています (基本的に、これは情報をログ ファイルに記録し、これらのファイルを日付 (年/月... 自動的に) で整理することを目的としています)。

ブートストラップ ファイル (どこにでも含まれています) に Logger のインスタンスを作成して使用しています。

require 'lib/Logger.class.php';
$mainLogger = new Logger('./my_log_folder');

これにより$mainLogger、何かをログに記録する必要があるすべての関数でグローバルを設定し、メソッドを呼び出す前にロガーがインスタンス化されているかどうかを確認する必要があります。

function foo($bar){
    global $mainLogger;
    if( !is_null($mainLogger) ){
        // If the logger is instanciated, I can log my message
        $mainLogger->log('error', 'mysql-errors', "My error message lorem ipsum dolor sit amet", Logger::GRAN_MONTH);
    }
}

$mainLoggerこのツールを使いやすくし、コードを少なくするために、 (シングルトン デザイン パターンに近いもの)のインスタンス化と取得を処理する関数 (Logger クラスの外部) を作成することを考えていました。

function getLogger(){
    global $mainLogger;
    if( !isset($mainLogger) ){
        if( class_exists('Logger') ){
            // Instanciation of the main logger
            $mainLogger = new Logger('./my_log_folder');
        } else {
            // The Logger class doesn't exists, so we'll return a magical object to "mimic" the logger attributes & methods, thus avoiding fatal errors
            return new MagicalClass();
        }
    }
    return $mainLogger;
}

class MagicalClass {
    public function __get($name){
        return;
    }
    public function __call($name, $args){
        return $this; // Allow to chain calls to this class, like jQuery : getLogger->foo()->bar()...
    }
}

MagicalClass は、致命的なエラー (致命的なエラー: 未定義のメソッドへの呼び出し...) を回避することを目的としています。これは、たとえば (Logger.class.php を含めずに) これを呼び出すことによって発生する可能性があります。

getLogger->log('error', 'mysql-errors', "My error message lorem ipsum dolor sit amet", Logger::GRAN_MONTH);

_コール__getを使用すると、Logger クラスの属性またはメソッドを使用しようとしてもエラーは発生しません (エラー ログはオプションの機能であり、Logger が存在しない場合にアプリがクラッシュすることはありません)。

このアプローチについてどう思いますか?それは悪い考えですか? これは私にいくつかの問題を引き起こす可能性がありますか?

ありがとう

PS : Logger クラスを見たい場合は、私の Web サイトのこちらからダウンロードできます。

4

2 に答える 2

4

ここで説明している「問題」は、さまざまな方法で解決できます。最も一般的なのは次の 3 つです。

  1. の使用factory class。ファクトリ クラスは、ファクトリを生成するオブジェクトです。ファクトリ自体は、クラス内でグローバルに使用される静的またはシングルトン クラスです。

  2. の使用Dependency Injection。この手法では、ロガー クラスがクラスのコンストラクターに挿入されます。クラスは、後で使用するためにロガーへの参照を保持します。

  3. Inversion of Control(IoC) コンテナーの使用。これは 1 と 2 の組み合わせです。コンテナーは作成されたオブジェクトのリストを保持し、新しいオブジェクトが必要になると作成され、依存オブジェクトがコンストラクターに自動的に挿入されます。

例:

工場クラス

class Foo
{
  public function Bar()
  {
    $logger = ClassFactory::CreateLogger();

    $logger->log('error', 'mysql-errors', 
      "My error message lorem ipsum dolor sit amet", Logger::GRAN_MONTH);
  }
}

依存性注入

class Foo
{
  private $logger;

  public function __construct($logger)
  {
    $this->logger = $logger;
  }

  public function Bar()
  {
    $this->logger->log('error', 'mysql-errors', 
      "My error message lorem ipsum dolor sit amet", Logger::GRAN_MONTH);
  }
}
于 2012-10-10T20:47:44.500 に答える
1

この魔法のクラスが必要だとは思いません。

まず、このマジック クラスは を実装していないLoggerため、タイプヒンティング (これは良いことです) が機能しません。第 2 に、マジック クラスが を実装または拡張していないためLogger、どの IDE でもマジック クラスでオートコンプリートが表示されません。確かに悪いこと。

Logger以前にロードされていない場合は、マジック クラスのみが必要です。これは非常に基本的な障害であるため、検出は非常に簡単です。最も簡単な方法はLogger、現在マジック クラスを持つファイルに を含めることです。

一方、機能getLogger()が利用可能であることをどのように保証しますか? Loggerが利用できない場合、関数は同じである可能性があり、コードは同様に失敗します。

コードの改善: これは使用しないでください:

function getLogger(){
    global $mainLogger;

グローバル変数は必要ありません。後で取得するためにロガーを格納する変数のみが必要です。代わりに静的変数を使用します。

function getLogger(){
    static $mainLogger;

もしそうなら、この関数はファクトリクラスに直接入り、静的に呼び出される可能性があります。変数$mainLoggerは、おそらくプライベート スコープ内のクラスの静的プロパティになります。

于 2012-10-11T19:43:13.770 に答える