mirror of
https://github.com/php/doc-ru.git
synced 2025-08-16 18:22:04 +00:00

git-svn-id: https://svn.php.net/repository/phpdoc/ru/trunk@316593 c90b9560-bf6c-de11-be94-00142212c4b1
362 lines
14 KiB
XML
362 lines
14 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- EN-Revision: 88a88985b966ce3acdc7835984636921e862e4c2 Maintainer: irker Status: ready -->
|
||
<!-- Reviewed: yes -->
|
||
<!-- $Revision$ -->
|
||
<chapter xml:id="language.exceptions" xmlns="http://docbook.org/ns/docbook">
|
||
<title>Исключения</title>
|
||
|
||
<para>
|
||
Модель исключений (exceptions) в PHP 5 проще, чем в других языках программирования.
|
||
Исключение можно сгенерировать (как говорят, "выбросить") при помощи оператора
|
||
<literal>throw</literal>, и можно перехватить (или, как говорят, "поймать")
|
||
оператором <literal>catch</literal>. Код генерирующий исключение, должен
|
||
быть окружен блоком <literal>try</literal>, для того чтобы можно было
|
||
перехватить исключение. Каждый блок <literal>try</literal>
|
||
должен иметь как минимум один соответствующий ему блок <literal>catch</literal>.
|
||
Так же можно использовать несколько блоков <literal>catch</literal>,
|
||
перехватывающих различные классы исключений.
|
||
Нормальное выполнение (когда не генерируются исключения в блоках
|
||
<literal>try</literal> или когда класс сгенерированного исключения не
|
||
совпадает с классами, объявленными в соответствующих блоках
|
||
<literal>catch</literal>) будет продолжено за последним блоком
|
||
<literal>catch</literal>. Исключения так же могут быть сгенерированы (или
|
||
вызваны еще раз) оператором <literal>throw</literal>
|
||
внутри блока <literal>catch</literal>.
|
||
</para>
|
||
<para>
|
||
При генерации исключения код следующий за оператором
|
||
<literal>throw</literal> исполнен не будет, а PHP предпримет попытку найти
|
||
первый блок <literal>catch</literal>, перехватывающий исключение данного
|
||
класса. Если исключение не будет перехвачено, PHP выдаст сообщение об
|
||
ошибке: "<literal>Uncaught Exception ...</literal>" (Неперехваченное
|
||
исключение), если не был определен обработчик ошибок при помощи
|
||
функции <function>set_exception_handler</function>.
|
||
</para>
|
||
<para>
|
||
Генерируемый объект должен принадлежать классу <classname>Exception</classname>
|
||
или наследоваться от <classname>Exception</classname>. Попытка сгенерировать
|
||
исключение другого класса приведет к неисправимой ошибке.
|
||
</para>
|
||
<note>
|
||
<para>
|
||
Внутренние функции PHP в основном используют
|
||
<link linkend="ini.error-reporting">сообщения об ошибках</link>, и только
|
||
новые <link linkend="language.oop5">объектно-ориентированные</link>
|
||
расширения используют исключения. Однако, ошибки можно легко преобразовать
|
||
в исключения с помощью класса <link linkend="class.errorexception">ErrorException</link>.
|
||
</para>
|
||
</note>
|
||
<tip>
|
||
<para>
|
||
<link linkend="intro.spl">Стандартная библиотека PHP (SPL)</link> предоставляет
|
||
хороший набор <link linkend="spl.exceptions">встроенных классов исключений</link>.
|
||
</para>
|
||
</tip>
|
||
<example>
|
||
<title>Выброс исключений</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
function inverse($x) {
|
||
if (!$x) {
|
||
throw new Exception('Деление на ноль.');
|
||
}
|
||
else return 1/$x;
|
||
}
|
||
|
||
try {
|
||
echo inverse(5) . "\n";
|
||
echo inverse(0) . "\n";
|
||
} catch (Exception $e) {
|
||
echo 'Выброшено исключение: ', $e->getMessage(), "\n";
|
||
}
|
||
|
||
// Продолжение выполнения
|
||
echo 'Hello World';
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
0.2
|
||
Выброшено исключение: Деление на ноль.
|
||
Hello World
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
<example>
|
||
<title>Вложенные исключения</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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();
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
string(4) "foo!"
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
|
||
<sect1 xml:id="language.exceptions.extending">
|
||
<title>Наследование исключений</title>
|
||
<para>
|
||
Определенный пользователем класс исключения должен быть определен, как
|
||
класс расширяющий (наследующий) встроенный класс Exception. Ниже приведены методы и
|
||
свойства класса Exception, доступные дочерним классам.
|
||
</para>
|
||
<example>
|
||
<title>Встроеный класс Exception</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
class Exception
|
||
{
|
||
protected $message = 'Unknown exception'; // Сообшение
|
||
private $string; // Свойство для __toString
|
||
protected $code = 0; // Код исключения,
|
||
// определяемый пользователем
|
||
protected $file; // Файл в котором было
|
||
// выброшено исключение
|
||
protected $line; // Строка в которой было
|
||
// выброшено исключение
|
||
private $trace; // Трассировка вызовов методов и функций
|
||
private $previous; // Предыдущее исключение, для
|
||
// вложенных блоков try
|
||
|
||
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 getTraceAsString(); // Трассировка вызовов как строка
|
||
|
||
/* Переопределяемое */
|
||
public function __toString(); // форматированная строка для отображения
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
<para>
|
||
Если класс, наследуемый от Exception переопределяет <link
|
||
linkend="language.oop5.decon">конструктор</link>, необходимо вызвать в
|
||
конструкторе <link linkend="language.oop5.paamayim-nekudotayim"
|
||
>parent::__construct()</link>, чтобы быть уверенным, что все дынные
|
||
будут доступны. Метод <link linkend="language.oop5.magic">__toString()</link>
|
||
может быть переопределен, что бы обеспечить нужный вывод, когда объект
|
||
преобразуется в строку.
|
||
</para>
|
||
<note>
|
||
<para>
|
||
Исключения нельзя клонировать. Попытка <link
|
||
linkend="language.oop5.cloning">клонировать</link> исключение приведет
|
||
к неисправимой ошибке <constant>E_ERROR</constant>.
|
||
</para>
|
||
</note>
|
||
<example>
|
||
<title>Наследование класса Exception (PHP 5.3.0+)</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
/**
|
||
* Определим свой класс исключения
|
||
*/
|
||
class MyException extends Exception
|
||
{
|
||
// Переопределим исключение так, что параметр message станет обязательным
|
||
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 "Мы можем определять новые методы в наследуемом классе\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 - неправильный параметр', 5);
|
||
break;
|
||
|
||
case self::THROW_DEFAULT:
|
||
// Бросаем встроеное исключение
|
||
throw new Exception('2 - недопустимый параметр', 6);
|
||
break;
|
||
|
||
default:
|
||
// Никаких исключений, объект будет создан.
|
||
$this->var = $avalue;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// Example 1
|
||
try {
|
||
$o = new TestException(TestException::THROW_CUSTOM);
|
||
} catch (MyException $e) { // Will be caught
|
||
echo "Поймано собственное переопределенное исключение\n", $e;
|
||
$e->customFunction();
|
||
} catch (Exception $e) { // Будет пропущено.
|
||
echo "Поймано встроенное исключение\n", $e;
|
||
}
|
||
|
||
// Отсюда будет продолжено выполнение программы
|
||
var_dump($o); // Null
|
||
echo "\n\n";
|
||
|
||
|
||
// Example 2
|
||
try {
|
||
$o = new TestException(TestException::THROW_DEFAULT);
|
||
} catch (MyException $e) { // Тип исключения не совпадет
|
||
echo "Поймано переопределенное исключение\n", $e;
|
||
$e->customFunction();
|
||
} catch (Exception $e) { // Будет перехвачено
|
||
echo "Перехвачено встроенное исключение\n", $e;
|
||
}
|
||
|
||
// Отсюда будет продолжено выполнение программы
|
||
var_dump($o); // Null
|
||
echo "\n\n";
|
||
|
||
|
||
// Example 3
|
||
try {
|
||
$o = new TestException(TestException::THROW_CUSTOM);
|
||
} catch (Exception $e) { // Будет перехвачено.
|
||
echo "Поймано встроенное исключение\n", $e;
|
||
}
|
||
|
||
// Продолжение исполнения программы
|
||
var_dump($o); // Null
|
||
echo "\n\n";
|
||
|
||
|
||
// Example 4
|
||
try {
|
||
$o = new TestException();
|
||
} catch (Exception $e) { // Будет пропущено, т.к. исключение не выбрасывается
|
||
echo "Поймано встроенное исключение\n", $e;
|
||
}
|
||
|
||
// Продолжение выполнения программы
|
||
var_dump($o); // TestException
|
||
echo "\n\n";
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
<note>
|
||
<para>
|
||
PHP 5 до версии 5.3.0 не поддерживает вложенные исключения.
|
||
Если есть необходимость запустить вышеприведенный пример в указанных версиях PHP,
|
||
то нужно заменить класс MyException.
|
||
</para>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
/**
|
||
* Определим свой класс исключения
|
||
*/
|
||
class MyException extends Exception
|
||
{
|
||
// Переопределим исключение так, что параметр message станет обязательным
|
||
public function __construct($message, $code = 0) {
|
||
// некоторый код
|
||
|
||
// убедитесь, что все передаваемые параметры верны
|
||
parent::__construct($message, $code);
|
||
}
|
||
|
||
// Переопределим строковое представление объекта.
|
||
public function __toString() {
|
||
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
|
||
}
|
||
|
||
public function customFunction() {
|
||
echo "Мы можем определять новые методы в наследуемом классе\n";
|
||
}
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</note>
|
||
</example>
|
||
</sect1>
|
||
|
||
</chapter>
|
||
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|