質問

PHPが失敗した場合に備えて、PHPのSPL Autoloaderから例外をスローする方法はありますか? PHP 5.2.11では機能していないようです。

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';
}

上記のコードが呼び出されると、例外の兆候はありません。代わりに、標準的な「致命的なエラー:class 'foobardomain' blaにはない」が得られます。スクリプトの実行が終了します。

役に立ちましたか?

解決

これはバグではありません 設計上の決定:

ノート: :スローされた例外 __autoload 関数をにとらえることはできません catch ブロックし、致命的なエラーをもたらします。

その理由は、複数のオートロードハンドラーが存在する可能性があるため、最初のハンドラーに例外を投げかけてセカンドハンドラーをバイパスすることは望ましくありません。セカンドハンドラーにクラスを自動装着する機会があることを望みます。オートローディング機能を使用するライブラリを使用する場合、オートロードの内部に例外を投げるため、オートロードハンドラーをバイパスする必要はありません。

クラスをインスタンス化できるかどうかを確認する場合は、使用してください class_exists とパス true 2番目の議論として(またはそれを除外して、 true デフォルトです):

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

他のヒント

コメントによると spl_autoload_registerのドキュメント, 、Autoloaderから別の関数を呼び出すことができ、それが例外をスローするでしょう。

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';
}

これは、自動ロード、名前空間のサポート、非静的なインスタンス(可変パスを使用)からの呼び出し、ロードエラーの処理、カスタム例外を示す本格的な工場オブジェクトです。

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( "不明な通貨プロバイダー国名ウクライナ"))

swisscurrencies.phpファイルがない場合 /currencyproviders /、

jj systemConfigurationException( 'Factory JJ CurrencyProvidersは新しいクラスバンクを生産することができませんでした SwissCurrencies。 、namespace = banks 、map:{"ドイツ": "germanbankcurrencies"、 "Switzerland": "swissbankcurrencies"} ')

十分な労力で、この工場を拡張して解析エラーをキャッチできます(phpでrequire()またはinclude()のエラーをキャッチする方法は?)そして、建設業者に引数を渡します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top