2009-10-16 17 views
5

PHPでSPLオートローダから例外をスローする方法はありますか? PHP 5.2.11では動作しないようです。上記のコードが呼び出されるSPLオートローダの例外のスロー?

class SPLAutoLoader{ 

    public static function autoloadDomain($className) { 
     if(file_exists('test/'.$className.'.class.php')){ 
      require_once('test/'.$className.'.class.php'); 
      return true; 
     }  

     throw new Exception('File not found'); 
    } 

} //end class 

//start 
spl_autoload_register(array('SPLAutoLoader', 'autoloadDomain')); 

try{ 
    $domain = new foobarDomain(); 
}catch(Exception $c){ 
    echo 'File not found'; 
} 

は、代わりに私は、標準的な取得、例外の兆候が存在しない「致命的なエラー:クラスのfoobarDomain "BLAには見られません」。スクリプトの実行が終了します。

+0

正確にはどうなりますか?あなたはそれが失敗したと言いましたが、失敗する方法はありません。 – Charles

+0

上記のコードが呼び出されると、例外の兆候はなく、代わりに標準の "致命的なエラー:クラス 'foobarDomain'がblaに見つかりません。スクリプトの実行が終了します。 – clops

+0

よかった、ありがとう。あなたが包含の前に例外を最初の関数にスローするとどうなりますか? – Charles

答えて

17

これはa design decisionだ、バグではありません。

Note: Exceptions thrown in __autoload function cannot be caught in the catch block and results in a fatal error.

理由は、あなたがスローする最初のハンドラをしたくない、その場合には、複数の自動ロード・ハンドラがあるかもしれないということですExceptionを呼び出し、2番目のハンドラをバイパスします。 2番目のハンドラがそのクラスをオートロードする機会を持つことを望みます。自動ロード機能を使用するライブラリを使用している場合、オートローダ内部でExceptionsをスローするため、オートロードハンドラをバイパスする必要はありません。

あなたは(trueがデフォルトである、またはそれを残して)、その後class_existsを使用し、2番目の引数としてtrueを渡し、あなたがクラスをインスタンス化できるかどうかを確認したい場合は、次の

if (class_exists('foobarDomain', $autoload = true)) { 
    $domain = new foobarDomain(); 
} else { 
    echo 'Class not found'; 
} 
+0

ありがとうございました - あなたは今日を保存しました! – clops

+2

この動作はPHP 5.3で変更されました - 例外がスローされ、オートローダで捕捉されるようになりました。ただし、オートローダが複数登録されている場合は注意が必要です。 – MrWhite

2

the documentation for spl_autoload_registerのコメントによれば、オートローダから別の関数を呼び出すことができます。これは、例外をスローします。

class SPLAutoLoader{ 

    public static function autoloadDomain($className) { 
     if(file_exists('test/'.$className.'.class.php')){ 
      require_once('test/'.$className.'.class.php'); 
      return true; 
     }  
     self::throwFileNotFoundException(); 
    } 

    public static function throwFileNotFoundException() 
    { 
     throw new Exception('File not found'); 
    } 

} //end class 

//start 
spl_autoload_register(array('SPLAutoLoader', 'autoloadDomain')); 

try{ 
    $domain = new foobarDomain(); 
}catch(Exception $c){ 
    echo 'File not found'; 
} 
+0

残念ながら、これは動作しません。同じエラーと例外はスローされません:( – clops

1

はここでいっぱいです自動ロード、名前空間サポート、非静的インスタンスからの呼び出し可能ファイル(変数パスを使用)、ロードエラーおよびカスタム例外の処理を実証する、完全なファクトリオブジェクトです。

abstract class AbstractFactory implements \ArrayAccess 
{ 
    protected $manifest; 
    function __construct($manifest) 
    { 
     $this->manifest = $manifest; 
    } 

    abstract function produce($name); 

    public function offsetExists($offset) 
    { 
     return isset($this->manifest[$offset]); 
    } 

    public function offsetGet($offset) 
    { 
     return $this->produce($offset); 
    } 
    //implement stubs for other ArrayAccess funcs 
} 


abstract class SimpleFactory extends AbstractFactory { 

    protected $description; 
    protected $path; 
    protected $namespace; 

    function __construct($manifest, $path, $namespace = "jj\\") { 
     parent::__construct($manifest); 
     $this->path = $path; 
     $this->namespace = $namespace; 
     if (! spl_autoload_register(array($this, 'autoload'), false)) //throws exceptions on its own, but we want a custom one 
      throw new \RuntimeException(get_class($this)." failed to register autoload."); 
    } 

    function __destruct() 
    { 
     spl_autoload_unregister(array($this, 'autoload')); 
    } 

    public function autoload($class_name) { 
     $file = str_replace($this->namespace, '', $class_name); 
     $filename = $this->path.$file.'.php'; 
     if (file_exists($filename)) 
      try { 
       require $filename; //TODO add global set_error_handler and try clause to catch parse errors 
      } catch (Exception $e) {} //autoload exceptions are not passed by design, nothing to do 
    } 

    function produce($name) { 
     if (isset($this->manifest[$name])) { 
      $class = $this->namespace.$this->manifest[$name]; 
      if (class_exists($class, $autoload = true)) { 
       return new $class(); 
      } else throw new \jj\SystemConfigurationException('Factory '.get_class($this)." was unable to produce a new class {$class}", 'SYSTEM_ERROR', $this); 
//an example of a custom exception with a string code and data container 

     } else throw new LogicException("Unknown {$this->description} {$name}."); 
    } 

    function __toString() //description function if custom exception class wants a string explanation for its container 
    { 
     return $this->description." factory ".get_class($this)."(path={$this->path}, namespace={$this->namespace}, map: ".json_encode($this->manifest).")"; 
    } 

} 

、最終的には例:いいえがある場合は

namespace jj; 
require_once('lib/AbstractFactory.php'); 
require_once('lib/CurrenciesProvider.php'); //base abstract class for all banking objects that are created 

class CurrencyProviders extends SimpleFactory 
{ 
    function __construct() 
    { 
     $manifest = array(
      'Germany' => 'GermanBankCurrencies', 
      'Switzerland' => 'SwissBankCurrencies' 
     ); 

     parent::__construct($manifest, __DIR__.'/CurrencyProviders/', //you have total control over relative or absolute paths here 
     'banks\'); 
     $this->description = 'currency provider country name'; 
    } 


} 

は今

$currencies_cache = (new \jj\CurrencyProviders())['Germany']; 

または

$currencies_cache = (new \jj\CurrencyProviders())['Ukraine']; 

LogicException("Unknown currency provider country name Ukraine")

を行いますこの工場は、エラー(How to catch error of require() or include() in PHP?)を解析し、コンストラクタに引数を渡すキャッチするように拡張することができ、十分な努力で/ CurrencyProviders SwissCurrencies.phpファイル/、

\jj\SystemConfigurationException('Factory jj\CurrencyProviders was unable to produce a new class banks\SwissCurrencies. Debug data: currency provider country name factory jj\CurrencyProviders(path=/var/www/hosted/site/.../CurrencyProviders/, namespace=banks\, map: {"Germany": "GermanBankCurrencies", "Switzerland":"SwissBankCurrencies"}')

関連する問題