2009-10-16 2 views
5

Başarısız olması durumunda PHP'de SPL Autoloader'dan istisnalar atmanın bir yolu var mı? PHP 5.2.11 altında çalışmak görünmüyor. Yukarıdaki kod denirSPL otomatik yükleyicide Özel durumlar mı atıyorsunuz?

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

, bunun yerine standart bir olsun, bir istisna hiçbir iz yoktur "Önemli hata: Class 'foobarDomain' bla bulunamadı". Ve betiğin yürütülmesi sona erer.

+0

Tam olarak ne olur? Sadece başarısız olduğunu söyledin, ama nasıl başarısız olduğunu değil. – Charles

+0

Yukarıdaki kod çağrıldığında, bir istisna belirtisi yoktur, bunun yerine standart bir "Önemli hata: Sınıf 'foobarDomain', bla içinde bulunamadı" standardı alıyorum. Ve betiğin yürütülmesi sona erer. – clops

+0

Harika, teşekkürler. İşe alınmadan önce istisna ilk şey işlevine bastığınızda ne olur? – Charles

cevap

17

Bu, bu a design decision bir böcek değildir:

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

nedeni birden fazla özdevinimli_yükle yükleyiciler, bu durumda, sen atmak ilk işleyici istemiyoruz olabileceğini olduğunu Bir İstisna ve ikinci işleyiciyi atla. İkinci işleyicinizin sınıflarını otomatik olarak yükleme şansı olmasını istersiniz. Otomatik yükleme özelliğini kullanan bir kitaplık kullanırsanız, otomatik yükleyicinizin baypas edilmesini istemezsiniz çünkü otomatik yükleyicilerinin içine Özel Durumlar atarlar.

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

Çok teşekkür ederim - günü kurtardınız! – clops

+2

Bu davranış PHP 5.3'te değişti - artık istisnalar atılabilir ve otomatik yükleyicide yakalanabilir.Bununla birlikte, kayıtlı birden çok otomatik yükleyiciniz varsa dikkatli olmanız gerekir. – MrWhite

2

the documentation for spl_autoload_register'daki yorumlara göre, otomatik yükleyiciden başka bir işlevi çağırmak mümkündür; bu da istisnayı atar.

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

Ne yazık ki bu işe yaramıyor. Aynı hata ve bir istisna atılmadı :( – clops

1

İşte tam açıklanmıştır:

Eğer class_exists kullanmak ve ikinci argüman olarak true geçmesi ardından, bir sınıf örneğini olup olmadığını kontrol etmek istiyorsanız

(ya da dışarıda bırakın, true varsayılan) otomatik yükleme, ad alanları desteği, durağan olmayan örneklerden (değişken yollar ile), yükleme hatalarının ve özel istisnaların işlenmesini gösteren fabrika nesnesi.
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).")"; 
    } 

} 

ve son olarak bir örnek

:

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


} 

şimdi yapmak

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

veya

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

LogicException("Unknown currency provider country name Ukraine")

hiçbir yoksa/CurrencyProviders/in SwissCurrencies.php dosyası, yeterli çaba ile

\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"}')

bu fabrika hataları (How to catch error of require() or include() in PHP?) ayrıştırması yakalamak ve kurucular argüman geçmek uzatılabilir.