2011-11-03 7 views
1

MVCのパラダイムをより深く理解するために、私自身のフレームワークを構築することを試しています。カスタムspl_autloader関数からエラーをキャプチャする最良の方法

エラーが発生したインクルードの結果であるPHPの醜いエラー/警告に頼るのではなく、スタックトレースとともにデータをより人間が読める形式で表示する一般的な例外クラスを設定します。

ここで私はこれまで...

spl_autoload_register(__NAMESPACE__.'\Autoloader::coreLoader'); 
spl_autoload_register(__NAMESPACE__.'\Autoloader::appLoader'); 
spl_autoload_register(__NAMESPACE__.'\Autoloader::throwException'); 

class Autoloader 
{ 
    private static $isError = false; 

    private static function loadHelper($className) 
    { 
     //Relevant code here 
    } 

    public static function coreLoader($className) 
    { 
     $classPath = static::loadHelper($className); 

     if ([email protected] PRIVATE_ROOT.DIRECTORY_SEPARATOR.$classPath.PHPEXT) 
     { 
      static::$isError = true; 
     } 
     else 
     { 
      static::$isError = false; 
     } 
    } 

    public static function appLoader($className) 
    { 
     $classPath = static::loadHelper($className); 

     if ([email protected] SYSTEM_PATH.DIRECTORY_SEPARATOR.$classPath.PHPEXT) 
     { 
      static::$isError = true; 
     } 
     else 
     { 
      static::$isError = false; 
     } 
    } 

    public static function throwException($className) 
    { 
     if (static::$isError) 
     { 
      throw new Exception_General('Attempted to load file: '.$className); 
     } 
    } 
} 

は、ファイルが見つからない場合includeが例外を生成しない、私はtry/catchブロックを使用することができないという事実を考えるとしているコードです。

try/catchブロックの代わりに、上記のコードのようにif statementを使用して、includeステートメントが必要なファイルのロードに成功したかどうかを確認できます。

私のException_Generalクラスは、開発者に便利なエラー出力/メッセージの生成と表示を担当します。私がここで直面する問題は、正当なオートローディング方法の中で例外をスローすると、スクリプトが正当に停止するということです。

最初の自動ロードメソッドが要求されたクラスを見つけられないかもしれないが、spl_autoloadキューの2番目または3番目のオートロードメソッドが要求されたファイル/クラスを見つけることができるので、これは理想的ではない。

この動作に対応するために、キュー内で最後に呼び出される第3の「偽の」オートロードメソッドを作成しなければならないことがわかりました。このメソッドはエラーフラグをチェックし、例外がスローされます。

私が本当に求めているのは、失敗したインクルードを取り込むための良い方法があり、すべてのオートローディング機能がそのコースを実行したら、適切に動作するかどうかです。

答えて

0

免責事項:特に、いくつかのコールバックが複製されるため、これは素晴らしい解決策であるとは必ずしも言えませんが、私はそれをインスピレーションの潜在的なソースとして挙げています。

私はちょうどこれを使っていましたが、オートロードの試行で使用されると、クラスが見つからない場合にシーケンスの最後に例外がスローされるオートロードメソッドがありました。これは、オートローディングプロシージャが実行されている間にオートロードスタックを変更し、オートロードを再帰的に呼び出すことによって行います。このウィザードの利点は、すべてのコールバックが失敗した場合にのみ例外がスローされ、後で登録されたコールバックを妨げるダミーのコールバックは必要ないということです。これで

function a() { echo "a\n"; } 
function b() { echo "b\n"; } 

class Autoloader { 
    // This prevents infinite recursion. 
    static $loading = false; 

    // This is the callback for this autoloader, for convenience. 
    static $callback = ['Autoloader', 'autoload']; 

    static function autoload($class_name) { 
    if(!static::$loading) { 
     // Basically what we do here is repeat the autoload cycle, and if it fails 
     // throw an exception. 
     $autoloaders = spl_autoload_functions(); // All registered autoloaders. 
     $priority = array_search(static::$callback, $autoloaders); 
     $past = []; // An array for callbacks that have already occurred. 
     for($i = 0; $i < $priority; $i++) { 
     $past[] = $autoloaders[$i]; // Fill the past events 
     spl_autoload_unregister($autoloaders[$i]); // Remove it from the stack 
     } 
     // We have now taken off the callbacks that ran before this one 

     static::$loading = true; // Make sure we don't get stuck. 
     spl_autoload_call($class_name); // 'Resume' autoloading. 
     static::$loading = false; // Reset for next time. 

     // We now need to put the other callbacks back in. 
     for($i = count($past) - 1; $i >= 0; $i--) 
     spl_autoload_register($past[$i], true, true); 

     if(class_exists($class_name)) 
     return true; // All is well 
     throw new Exception('could not find class '.$class_name); // Not so well... 
    } else { 
     echo "Autoloader::autoload\n"; 
    } 
    } 
} 

spl_autoload_register('a'); 
spl_autoload_register(Autoloader::$callback); 
spl_autoload_register('b'); 

new Foo; // Would print `a, Autoloader::autoload, b` then the exception message. 

1つの警告は、例外が実際に自動ロードチェーンの外に中断されませんようAutoloader::autoload後に発生コールバックは、二回起こるだろうということです。例外を発生させる前にこれらのコールバックを削除することは可能ですが、例外がキャッチされた場合はオートロードシーケンスが壊れます(たとえば、['a', 'Autoloader...', 'c']がスタックにあり、クラスが見つからない場合はcがコードの2倍cが1回発生するようにコードを修正することができますが、例外がキャッチされた場合は自動ロードスタックは['a', 'Autoloader...']のままになります。

+0

私は複数のオートローダーのルートを選択した理由の1つは、パフォーマンス/速度によるものです。1つのautoload関数のみを使用し、その関数内でクラス名文字列を解析/照合するルートに進むと、例外を含むことができるので、例外をスローすることに問題はありません。このアプローチの欠点は、単純にクラスをロードするために多くの処理能力を発揮することです。複数のオートローダーでは、各オートローダーがクラス/パスの特定のセグメントを担当するため、処理があまり行われません。 – cgons

+0

あなたはもちろんそうです。あなたが言うように、各クラスを見つけるオーバーヘッドはかなり高いので、プロダクション環境で使用するとは思えません。これは、すべてのコールバックが失敗した場合(つまり、「Autoloader」の後に追加されたものであっても)、例外がスローされることを確実にするというアイデアによって、多かれ少なかれ動いていました。私がそれを投稿したときの私の就寝時間をはるかに過ぎた)。 – connec

関連する問題