الفرق بين المراجعتين لصفحة: «PHP/exceptions»
إعادة هيكلة الصفحة |
رؤيا-بنعطية (نقاش | مساهمات) لا ملخص تعديل |
||
(6 مراجعات متوسطة بواسطة مستخدم واحد آخر غير معروضة) | |||
سطر 6: | سطر 6: | ||
يمكن استخدام كتل <code>catch</code> متعدّدة لالتقاط أصناف مختلفة من الاستثناءات. تستمر عملية تنفيذ الشيفرة الاعتيادية (في حال عدم رمي أي استثناء في الكتلة block) بعد آخر كتلة <code>catch</code> معرّفة في الشيفرة. يمكن رمي الاستثناءات (أو إعادة رميها) ضمن الكتلة <code>catch</code>. | يمكن استخدام كتل <code>catch</code> متعدّدة لالتقاط أصناف مختلفة من الاستثناءات. تستمر عملية تنفيذ الشيفرة الاعتيادية (في حال عدم رمي أي استثناء في الكتلة block) بعد آخر كتلة <code>catch</code> معرّفة في الشيفرة. يمكن رمي الاستثناءات (أو إعادة رميها) ضمن الكتلة <code>catch</code>. | ||
لا تنفّذ الشيفرة التي تلي العبارة التي تسبّبت في رمي الاستثناء، وتحاول اللغة العثور على أول كتلة catch مطابقة. في حال عدم التقاط الاستثناء، تطلق اللغة خطأ من نوع PHP مع رسالة "Uncaught Exception ..." إلا إذا كان هناك متحكّم معرّف بواسطة الدالة <code>[[PHP/ | لا تنفّذ الشيفرة التي تلي العبارة التي تسبّبت في رمي الاستثناء، وتحاول اللغة العثور على أول كتلة catch مطابقة. في حال عدم التقاط الاستثناء، تطلق اللغة خطأ من نوع PHP مع رسالة "Uncaught Exception ..." إلا إذا كان هناك متحكّم معرّف بواسطة الدالة <code>[[PHP/set_exception_handler|set_exception_handler()]]</code>. | ||
في الإصدار 7.1 وما بعده من اللغة، يمكن لكتلة <code>catch</code> أن تحدّد استثناءات متعددة باستخدام الرمز (<code>|</code>). هذه الميزة مفيدة عندما تتعامل اللغة بالطريقة نفسها مع استثناءات مختلفة من تسلسلات هرمية لأصناف مختلفة. | في الإصدار 7.1 وما بعده من اللغة، يمكن لكتلة <code>catch</code> أن تحدّد استثناءات متعددة باستخدام الرمز (<code>|</code>). هذه الميزة مفيدة عندما تتعامل اللغة بالطريقة نفسها مع استثناءات مختلفة من تسلسلات هرمية لأصناف مختلفة. | ||
سطر 43: | سطر 43: | ||
يعطي المثال السابق المخرجات التالية: | يعطي المثال السابق المخرجات التالية: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="text"> | ||
0.2 | 0.2 | ||
سطر 83: | سطر 83: | ||
يعطي المثال السابق المخرجات التالية: | يعطي المثال السابق المخرجات التالية: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="text"> | ||
0.2 | 0.2 | ||
سطر 121: | سطر 121: | ||
يعطي المثال السابق المخرجات التالية: | يعطي المثال السابق المخرجات التالية: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="text"> | ||
string(4) "foo!" | string(4) "foo!" | ||
سطر 151: | سطر 151: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
يعطي المثال السابق المخرجات التالية: | يعطي المثال السابق المخرجات التالية: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="text"> | ||
string(11) "MyException" | string(11) "MyException" | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == توسيع الاستثناءات == | ||
يمكن تعريف | يمكن تعريف صنف <code>Exception</code> خاص من قبل المستخدم وذلك بتوسيع الصنف <code>Exception</code> المُضمَّن في اللغة، ويوضّح المثال التالي التوابع والخواصّ المتاحة للاستخدام في الصنف الابن المُشتقّ من الصنف <code>Exception</code> الداخلي. | ||
المثال 5: الصنف <code>Exception</code> الداخلي<syntaxhighlight lang="php"> | |||
<?php | |||
class Exception | |||
{ | |||
protected $message = 'Unknown exception'; | |||
// exception message | |||
private $string; | |||
// __toString التقاط | |||
protected $code = 0; | |||
// شيفرة الاستثناء المعرّفة من قبل المستخدم | |||
protected $file; | |||
// اسم الملف المصدري الخاص بالاستثناء | |||
protected $line; | |||
// السطر المصدري الخاص بالاستثناء | |||
private $trace; | |||
// backtrace | |||
private $previous; | |||
// الصنف السابق في حال كان الاستثناء متداخلًا | |||
public function __construct($message = null, $code = 0, Exception $previous = null); | |||
final private function __clone(); | |||
// يمنع استنساخ الاستثناء | |||
final public function getMessage(); | |||
// رسالة الاستثناء | |||
final public function getCode(); | |||
// شيفرة الاستثناء | |||
final public function getFile(); | |||
// اسم ملف المصدر | |||
final public function getLine(); | |||
// سطر المصدر | |||
final public function getTrace(); | |||
// مصفوفة التابع backtrace() | |||
final public function getPrevious(); | |||
// الاستثناء السابق | |||
final public function getTraceAsString(); | |||
// سلسلة نصّية منسقة trace | |||
// يمكن إعادة تعريفها | |||
public function __toString(); | |||
// سلسلة نصية منسّقة لغرض العرض | |||
} | |||
?> | |||
</syntaxhighlight>في حال وراثة أي صنف للصنف الداخلي <code>Exception</code> وإعادة تعريفه للتابع الباني، فينصح بشدّة استدعاء التابع الأب <code>parent::__construct()</code> لضمان إسناد جميع البيانات المتاحة بصورة صحيحة. يمكن إعادة تعريف التابع <code>__toString()</code> لتقديم مخرجات خاصة عند عرض الكائن على هيئة سلسلة نصّية. | |||
ملاحظة: لا يمكن استنساخ الاستثناءات، وتؤدي محاولة استنساخها إلى حدوث خطأ من نوع E_ERROR. | |||
المثال 6: توسيع الصنف <code>Exception</code> في الإصدار 5.3.0 وما بعده من PHP<syntaxhighlight lang="php"> | |||
<?php | |||
// تعريف صنف Exception خاص | |||
class MyException extends Exception | |||
{ | |||
إعادة تعريف الاستثناء لتصبح الرسالة معاملًا إلزاميًا | |||
public function __construct($message, $code = 0, Exception $previous = null) { | |||
// بعض الشيفرة هنا | |||
// التأكد من إسناد كل شيء بصورة صحيحة | |||
parent::__construct($message, $code, $previous); | |||
} | |||
// تمثيل الكائن على هيئة سلسلة نصّية ذات تنسيق خاص | |||
public function __toString() { | |||
return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; | |||
} | |||
public function customFunction() { | |||
echo "A custom function for this type of exception\n"; | |||
} | |||
} | |||
// إنشاء صنف لاختبار الاستثناء | |||
class TestException | |||
{ | |||
public $var; | |||
const THROW_NONE = 0; | |||
const THROW_CUSTOM = 1; | |||
const THROW_DEFAULT = 2; | |||
function __construct($avalue = self::THROW_NONE) { | |||
switch ($avalue) { | |||
case self::THROW_CUSTOM: | |||
// رمي استثناء خاص | |||
throw new MyException('1 is an invalid parameter', 5); | |||
break; | |||
case self::THROW_DEFAULT: | |||
// رمي استثناء اعتيادي | |||
throw new Exception('2 is not allowed as a parameter', 6); | |||
break; | |||
default: | |||
// لا يوجد استثناء، وسيُنشئ الكائن | |||
$this->var = $avalue; | |||
break; | |||
} | |||
} | |||
} | |||
// المثال 1 | |||
try { | |||
$o = new TestException(TestException::THROW_CUSTOM); | |||
} catch (MyException $e) { | |||
// سيُلتقط الاستثناء | |||
echo "Caught my exception\n", $e; | |||
$e->customFunction(); | |||
} catch (Exception $e) { | |||
// سيتم تجاوز الاستثناء | |||
echo "Caught Default Exception\n", $e; | |||
} | |||
// الاستمرار في تنفيذ الشيفرة | |||
var_dump($o); // Null | |||
echo "\n\n"; | |||
// المثال 2 | |||
try { | |||
$o = new TestException(TestException::THROW_DEFAULT); | |||
} catch (MyException $e) { | |||
// غير مطابق لهذا النوع | |||
echo "Caught my exception\n", $e; | |||
$e->customFunction(); | |||
} catch (Exception $e) { | |||
// سيلتقط الاستثناء | |||
echo "Caught Default Exception\n", $e; | |||
} | |||
// الاستمرار في تنفيذ الشيفرة | |||
var_dump($o); // Null | |||
echo "\n\n"; | |||
// المثال 3 | |||
try { | |||
$o = new TestException(TestException::THROW_CUSTOM); | |||
} catch (Exception $e) { | |||
// سيلتقط الاستثناء | |||
echo "Default Exception caught\n", $e; | |||
} | |||
// الاستمرار في تنفيذ الشيفرة | |||
var_dump($o); // Null | |||
echo "\n\n"; | |||
// المثال 4 | |||
try { | |||
$o = new TestException(); | |||
} catch (Exception $e) { | |||
// ستتجاوز اللغة هذه العبارة نظرًا لعدم وجود استثناء | |||
echo "Default Exception caught\n", $e; | |||
} | |||
// الاستمرار في تنفيذ الشيفرة | |||
var_dump($o); // TestException | |||
echo "\n\n"; | |||
?> | |||
</syntaxhighlight>ملاحظة: لا تدعم الإصدارات السابقة للإصدار 5.3.0 تداخل الاستثناءات، ويمكن استخدام الشيفرة التالية كبديل عن الصنف <code>MyException</code> إن كنت ترغب في تطبيق هذا المثال.<syntaxhighlight lang="php"> | |||
<?php | |||
// تعريف صنف استثناء خاص | |||
class MyException extends Exception | |||
{ | |||
// إعادة تعريف الاستثناء بحيث يصبح المعامل الأول إلزاميًا | |||
public function __construct($message, $code = 0) { | |||
// بعض الشيفرة هنا | |||
// التأكد من أن جميع عمليات الإسناد قد تمت بصورة صحيحة | |||
parent::__construct($message, $code); | |||
} | |||
// تمثيل الكائن على هيئة سلسلة نصّية ذات تنسيق خاص | |||
public function __toString() { | |||
return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; | |||
} | |||
public function customFunction() { | |||
echo "A custom function for this type of exception\n"; | |||
} | |||
} | |||
?> | |||
</syntaxhighlight> | |||
== مصادر == | == مصادر == | ||
* [http://php.net/manual/en/language.exceptions.php صفحة Exceptions في توثيق PHP الرسمي.] | * [http://php.net/manual/en/language.exceptions.php صفحة Exceptions في توثيق PHP الرسمي.] | ||
[[تصنيف:PHP]] | [[تصنيف:PHP|{{SUBPAGENAME}}]] | ||
[[تصنيف:PHP Exceptions]] | [[تصنيف:PHP Exceptions|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 22:43، 7 يونيو 2018
يتضمّن الإصدار الخامس من PHP نموذج استثناءات مشابهًا للغات البرمجية الأخرى. يمكن رمي الاستثناء والتقاطه في PHP، ويمكن إحاطة الشيفرة بكتلة try
لتسهيل عملية التقاط الاستثناءات المحتملة، ويجب أن ترتبط بكل كتلة try
إما كتلة catch
أو finally
واحدة على الأقل.
يجب أن يكون كائن الاستثناء المرمي نسخة من الصنف Exception
أو صنفًا متفرعًا منه، ويؤدي رمي كائن لا ينتمي إلى هذا الصنف إلى حدوث خطأ من نوع Fatal.
الكتلة catch
يمكن استخدام كتل catch
متعدّدة لالتقاط أصناف مختلفة من الاستثناءات. تستمر عملية تنفيذ الشيفرة الاعتيادية (في حال عدم رمي أي استثناء في الكتلة block) بعد آخر كتلة catch
معرّفة في الشيفرة. يمكن رمي الاستثناءات (أو إعادة رميها) ضمن الكتلة catch
.
لا تنفّذ الشيفرة التي تلي العبارة التي تسبّبت في رمي الاستثناء، وتحاول اللغة العثور على أول كتلة catch مطابقة. في حال عدم التقاط الاستثناء، تطلق اللغة خطأ من نوع PHP مع رسالة "Uncaught Exception ..." إلا إذا كان هناك متحكّم معرّف بواسطة الدالة set_exception_handler()
.
في الإصدار 7.1 وما بعده من اللغة، يمكن لكتلة catch
أن تحدّد استثناءات متعددة باستخدام الرمز (|
). هذه الميزة مفيدة عندما تتعامل اللغة بالطريقة نفسها مع استثناءات مختلفة من تسلسلات هرمية لأصناف مختلفة.
الكتلة finally
في الإصدار 5.5 من اللغة يمكن استخدام الكتلة block بعد أو بدلًا من كتل catch
. تُنفّذ الشيفرة الموجودة ضمن الكتلة finally
دائمًا بعد الشيفرة الموجودة في كتل try
و catch
بغض النظر عمّا إذا كان هناك استثناء مرمي، و قبل العودة إلى عملية تنفيذ الشيفرة الاعتيادية.
ملاحظات
ملاحظة: تستخدم دوال PHP الداخلية بصورة عامة التبليغ عن الأخطاء، أما الاستثناءات فتستخدم من طرف الملحقات الحديثة كائنية التوجّه فقط. ولكن يمكن تحويل الأخطاء ببساطة إلى استثناءات باستخدام الصنف ErrorException
.
نصيحة: تقدم مكتبة PHP القياسية (SPL) عددًا من الاستثناءات المدمجة المفيدة.
أمثلة
المثال 1: رمي استثناء
<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}
try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
// الاستمرار في عملية التنفيذ
echo "Hello World\n";
?>
يعطي المثال السابق المخرجات التالية:
0.2
Caught exception: Division by zero.
Hello World
المثال 2: التعامل مع الاستثناءات بواسطة كتلة finally
<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}
try {
echo inverse(5) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "First finally.\n";
}
try {
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "Second finally.\n";
}
// استمرار عملية التنفيذ
echo "Hello World\n";
?>
يعطي المثال السابق المخرجات التالية:
0.2
First finally.
Caught exception: Division by zero.
Second finally.
Hello World
المثال 3: استثناءات متداخلة
<?php
class MyException extends Exception { }
class Test {
public function testing() {
try {
try {
throw new MyException('foo!');
} catch (MyException $e) {
// رمي الاستثناء مرة أخرى
throw $e;
}
} catch (Exception $e) {
var_dump($e->getMessage());
}
}
}
$foo = new Test;
$foo->testing();
?>
يعطي المثال السابق المخرجات التالية:
string(4) "foo!"
المثال 4: كتل catch
متعددة للتعامل مع الاستثناءات
<?php
class MyException extends Exception { }
class MyOtherException extends Exception { }
class Test {
public function testing() {
try {
throw new MyException();
} catch (MyException | MyOtherException $e) {
var_dump(get_class($e));
}
}
}
$foo = new Test;
$foo->testing();
?>
يعطي المثال السابق المخرجات التالية:
string(11) "MyException"
توسيع الاستثناءات
يمكن تعريف صنف Exception
خاص من قبل المستخدم وذلك بتوسيع الصنف Exception
المُضمَّن في اللغة، ويوضّح المثال التالي التوابع والخواصّ المتاحة للاستخدام في الصنف الابن المُشتقّ من الصنف Exception
الداخلي.
المثال 5: الصنف Exception
الداخلي
<?php
class Exception
{
protected $message = 'Unknown exception';
// exception message
private $string;
// __toString التقاط
protected $code = 0;
// شيفرة الاستثناء المعرّفة من قبل المستخدم
protected $file;
// اسم الملف المصدري الخاص بالاستثناء
protected $line;
// السطر المصدري الخاص بالاستثناء
private $trace;
// backtrace
private $previous;
// الصنف السابق في حال كان الاستثناء متداخلًا
public function __construct($message = null, $code = 0, Exception $previous = null);
final private function __clone();
// يمنع استنساخ الاستثناء
final public function getMessage();
// رسالة الاستثناء
final public function getCode();
// شيفرة الاستثناء
final public function getFile();
// اسم ملف المصدر
final public function getLine();
// سطر المصدر
final public function getTrace();
// مصفوفة التابع backtrace()
final public function getPrevious();
// الاستثناء السابق
final public function getTraceAsString();
// سلسلة نصّية منسقة trace
// يمكن إعادة تعريفها
public function __toString();
// سلسلة نصية منسّقة لغرض العرض
}
?>
في حال وراثة أي صنف للصنف الداخلي Exception
وإعادة تعريفه للتابع الباني، فينصح بشدّة استدعاء التابع الأب parent::__construct()
لضمان إسناد جميع البيانات المتاحة بصورة صحيحة. يمكن إعادة تعريف التابع __toString()
لتقديم مخرجات خاصة عند عرض الكائن على هيئة سلسلة نصّية.
ملاحظة: لا يمكن استنساخ الاستثناءات، وتؤدي محاولة استنساخها إلى حدوث خطأ من نوع E_ERROR.
المثال 6: توسيع الصنف Exception
في الإصدار 5.3.0 وما بعده من PHP
<?php
// تعريف صنف Exception خاص
class MyException extends Exception
{
إعادة تعريف الاستثناء لتصبح الرسالة معاملًا إلزاميًا
public function __construct($message, $code = 0, Exception $previous = null) {
// بعض الشيفرة هنا
// التأكد من إسناد كل شيء بصورة صحيحة
parent::__construct($message, $code, $previous);
}
// تمثيل الكائن على هيئة سلسلة نصّية ذات تنسيق خاص
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function customFunction() {
echo "A custom function for this type of exception\n";
}
}
// إنشاء صنف لاختبار الاستثناء
class TestException
{
public $var;
const THROW_NONE = 0;
const THROW_CUSTOM = 1;
const THROW_DEFAULT = 2;
function __construct($avalue = self::THROW_NONE) {
switch ($avalue) {
case self::THROW_CUSTOM:
// رمي استثناء خاص
throw new MyException('1 is an invalid parameter', 5);
break;
case self::THROW_DEFAULT:
// رمي استثناء اعتيادي
throw new Exception('2 is not allowed as a parameter', 6);
break;
default:
// لا يوجد استثناء، وسيُنشئ الكائن
$this->var = $avalue;
break;
}
}
}
// المثال 1
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (MyException $e) {
// سيُلتقط الاستثناء
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) {
// سيتم تجاوز الاستثناء
echo "Caught Default Exception\n", $e;
}
// الاستمرار في تنفيذ الشيفرة
var_dump($o); // Null
echo "\n\n";
// المثال 2
try {
$o = new TestException(TestException::THROW_DEFAULT);
} catch (MyException $e) {
// غير مطابق لهذا النوع
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) {
// سيلتقط الاستثناء
echo "Caught Default Exception\n", $e;
}
// الاستمرار في تنفيذ الشيفرة
var_dump($o); // Null
echo "\n\n";
// المثال 3
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (Exception $e) {
// سيلتقط الاستثناء
echo "Default Exception caught\n", $e;
}
// الاستمرار في تنفيذ الشيفرة
var_dump($o); // Null
echo "\n\n";
// المثال 4
try {
$o = new TestException();
} catch (Exception $e) {
// ستتجاوز اللغة هذه العبارة نظرًا لعدم وجود استثناء
echo "Default Exception caught\n", $e;
}
// الاستمرار في تنفيذ الشيفرة
var_dump($o); // TestException
echo "\n\n";
?>
ملاحظة: لا تدعم الإصدارات السابقة للإصدار 5.3.0 تداخل الاستثناءات، ويمكن استخدام الشيفرة التالية كبديل عن الصنف MyException
إن كنت ترغب في تطبيق هذا المثال.
<?php
// تعريف صنف استثناء خاص
class MyException extends Exception
{
// إعادة تعريف الاستثناء بحيث يصبح المعامل الأول إلزاميًا
public function __construct($message, $code = 0) {
// بعض الشيفرة هنا
// التأكد من أن جميع عمليات الإسناد قد تمت بصورة صحيحة
parent::__construct($message, $code);
}
// تمثيل الكائن على هيئة سلسلة نصّية ذات تنسيق خاص
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function customFunction() {
echo "A custom function for this type of exception\n";
}
}
?>