ここでシングルトンを使用すると、Logger の依存関係が隠されます。ここではグローバルなアクセス ポイントは必要ありません。また、すでに DI に準拠しようとしているので、おそらくコードを散らかしてテスト不能にしたくないでしょう。
実際、それを実装するためのよりクリーンな方法があります。それを見てみましょう。
set_error_handler はオブジェクトを受け入れます
関数にクロージャまたは関数名を渡す必要はありませんset_error_handler
。ドキュメントの状態は次のとおりです。
次のシグネチャを持つコールバック。代わりに NULL を渡して、このハンドラーをデフォルトの状態にリセットすることができます。関数名の代わりに、オブジェクト参照とメソッド名を含む配列を指定することもできます。
これを知っていれば、専用のオブジェクトを使用してエラーを処理できます。オブジェクトのハンドラー メソッドは、次のように呼び出されます。set_error_handler
set_error_handler([$errorHandler, 'handle']);
where$errorHandler
は呼び出されるオブジェクトと handle
メソッドです。
エラーハンドラ
クラスはErrorHandler
エラー処理を担当します。クラスを使用することで得られる利点は、DI を簡単に利用できることです。
<?php
interface ErrorHandler {
public function handle( $errno, $errstr , $errfile = null , $errline = null , $errcontext = null );
}
class ConcreteErrorHandler implements ErrorHandler {
protected $logger;
public function __construct( Logger $logger = null )
{
$this->logger = $logger ?: new VoidLogger();
}
public function handle( $errno, $errstr , $errfile = null , $errline = null , $errcontext = null )
{
echo "Triggered Error Handler";
$this->logger->log('An error occured. Some Logging.');
}
}
このhandle()
方法については、これ以上説明する必要はありません。その署名は関数のニーズに準拠しておりset_error_handler()
、コントラクトを定義することでそれを確認します。
ここで興味深いのはコンストラクタです。Logger
ここでは (インターフェイス)をタイプヒントしており、null を渡すことができます。
<?php
interface Logger {
public function log( $message );
}
class ConcreteLogger implements Logger {
public function log( $message )
{
echo "Logging: " . $message;
}
}
渡されたLogger
インスタンスは、対応するプロパティに割り当てられます。ただし、何も渡されない場合は、a のインスタンスVoidLogger
が割り当てられます。DI の原則に反しますが、特定のパターンを使用しているため、その場合はまったく問題ありません。
Null オブジェクト パターン
あなたの基準の1つは次のとおりでした。
ロガーは開始される場合と開始されない場合があることに注意してください。アイデアは、何らかの方法で別のロガーを簡単に定義できるようにすることです。
Null オブジェクト パターンは、動作のないオブジェクトが必要であるが、コントラクトに従いたい場合に使用されます。
log()
ErrorHandler で Loggerのメソッドを呼び出すため、インスタンスが必要です(何もないメソッドを呼び出すことはできません)。Logger
しかし、何もしない Logger の具体的な実装を作成することを禁止する人は誰もいません。Null Object パターンはまさにそれです。
<?php
class VoidLogger implements Logger {
public function log( $message ){}
}
ここで、ロギングを有効にしたくない場合は、インスタンス化中にエラー ハンドラに何も渡さないか、VoidLogger
自分で a を渡します。
使用法
<?php
$errorHandler = new ConcreteErrorHandler(); // Or Pass a Concrete Logger instead
set_error_handler([$errorHandler, 'handle']);
echo $notDefined;
PSR ロガーを使用するには、型ヒントとロガーのメソッド呼び出しを少し調整する必要があります。しかし、原則は変わりません。
利点
このタイプの実装を選択すると、次の利点が得られます。
- エラー ハンドラ用の簡単に交換可能なロガー
- 簡単に交換可能なエラー ハンドラも
- 疎結合 (処理エラーからログを切り離す)
- 簡単に拡張可能なエラー ハンドラー (ロガーだけでなく、他のものを注入できます)