2009-10-16 5 views
5

PHP에서 SPL 자동 로더의 예외를 throw 할 수 있습니까? 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'즐에서 찾을 수 없습니다." 그리고 스크립트의 실행이 종료됩니다.

+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을 처리하고 두 번째 처리기를 우회합니다. 두 번째 처리기가 클래스를 자동로드 할 수있는 기회를 원합니다. 자동로드 기능을 사용하는 라이브러리를 사용하는 경우 자동로드 처리기를 거치지 않고 자동 로딩 처리기를 건너 뛰지 않아도됩니다. 자동로드 처리기가 자동 로더 내부에 예외를 발생시키기 때문입니다.

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

여기에 가득 :

당신이 class_exists을 사용하고 두 번째 인수로 true을 통과 한 후, 클래스를 인스턴스화 할 수 있는지 여부를 확인하려면

(또는 그것을두고는, true이 기본값입니다) 자동 로딩, 네임 스페이스 지원, 비 정적 인스턴스의 호출 가능 (변수 경로 포함), 로딩 오류 및 사용자 정의 예외 처리를 나타내는 팩토리 된 객체입니다.
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")

은 더는 존재하지 않는 경우/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"}')

이 공장은 오류 (How to catch error of require() or include() in PHP?를) 구문 분석 잡을 생성자에 인수를 전달하는 확장 할 수 있습니다.

관련 문제