سؤال
هل هناك طريقة لرمي الاستثناءات من SPL Autoloader في PHP في حالة فشلها؟ لا يبدو أنه يعمل تحت 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';
}
عندما يتم استدعاء الكود أعلاه ، لا توجد علامة على استثناء ، بدلاً من ذلك أحصل على "خطأ فادح: فئة" foobardomain "غير موجودة في BLA". وتنفيذ البرنامج النصي ينتهي.
المحلول
هذا ليس خطأ ، إنه كذلك قرار التصميم:
ملحوظة: استثناءات ألقيت في
__autoload
لا يمكن القبض على الوظيفة فيcatch
حظر ويؤدي إلى خطأ مميت.
والسبب هو أنه قد يكون هناك أكثر من معالجات التحميل التلقائي ، وفي هذه الحالة ، لا تريد أن يرمي المعالج الأول استثناء وتجاوز المعالج الثاني. تريد أن يكون لدى معالجك الثاني فرصة في التحميل التلقائي لدروسها. إذا كنت تستخدم مكتبة تستخدم ميزة التحميل التلقائي ، فأنت لا تريدها تجاوز معالج التحميل التلقائي لأنها ترمي استثناءات داخل التحميل التلقائي.
إذا كنت ترغب في التحقق مما إذا كان يمكنك إنشاء فصل دراسي أم لا ، فاستخدم class_exists
ويمر true
كحجة ثانية (أو اتركها ، 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';
}
فيما يلي كائن مصنع كامل المصنع يوضح التحميل التلقائي ، ودعم مساحات الأسماء ، و Callables من مثيلات غير منتظمة (مع مسارات متغيرة) ، ومعالجة أخطاء التحميل والاستثناءات المخصصة.
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. بيانات التصحيح: موفر العملة اسم البلاد مصنع jj currencyproviders (path =/var/www/site/site /.../ currencyproviders/ ، مساحة الاسم = البنوك ، الخريطة: {"ألمانيا": "GermanbankCurrencies" ، "Switzerland": "SwissBankCurrencies"} ')
مع جهد كافٍ ، يمكن تمديد هذا المصنع لالتقاط أخطاء تحليل (كيفية التقاط خطأ من المتطلبات () أو تضمين () في PHP؟) وتمرير الحجج إلى المُنشئين.