В PHP5 как и в других мощных языках программирования (например Java) существует механизм выброса и перехвата исключительных ситуаций.
Для этого необходимо поместить потенциально небезопасный код в блок try для перехвата исключения. Каждый try должен сопровождаться как минимум одним блоком catch.
Множественные блоки catch можно использовать для перехвата исключений различных классов. Меньше слов - больше дела:
class Generic
{
private $someVar;
public function __construct($someVar)
{
$this->someVar = $someVar;
}
public function testValue($someOtherVar)
{
if($someOtherVar > 3) {
throw new Exception('Значение параметра не божет быть больше 3!');
} else {
echo $this->someVar + $someOtherVar;
}
}
}
$gen = new Generic(3);
$gen->testValue(4);
Этот фрагмент кода превосходно демонстрирует процесс выброса исключения. Если вы сейчас запустите страницу с этим кодом, то получите сообщение на подобии этого:
Fatal error: Uncaught exception ‘Exception’ with message ‘Parameter can not be larger then 3!’ in C:\wamp\www\privat\codeforest\exceptions\index.php:15 Stack trace: #0 C:\wamp\www\privat\codeforest\exceptions\index.php(23): Generic->testValue(4) #1 {main} thrown in C:\wamp\www\privat\codeforest\exceptions\index.php on line 15
Это произошло из-за отсутствия блока try-catch. Исправим ситуацию следующим образом:
try
{
$gen = new Generic(3);
$gen->testValue(4);
} catch (Exception $e) {
// обработка исключения
echo 'Поймали исключение<br />';
echo 'Сообщение: ' . $e->getMessage() . '<br />';
echo 'Дополнительный текст!';
}
Теперь мы успешно поймали наше исключение. Доказательство этому сообщение на экране.
Так же существует возможность получения детальной информации при перехвате исключительной ситуации. Это полезно тогда, когда у вас выбрасываются десятки или сотни исключений. Для того, чтобы быстро найти код, где это произошло, можно воспользоваться специальными методами:
try
{
$gen = new Generic(3);
$gen->testValue(4);
} catch (Exception $e) {
// code to handle the Exception
echo 'Error :' . $e->getMessage() . '<br />';
echo 'Code :' . $e->getCode() . '<br />';
echo 'File :' . $e->getFile() . '<br />';
echo 'Line :' . $e->getLine() . '<br />';
exit();
}
Этот пример не сильно отличается от прошлого. Тут мы используем методы объекта, сгенерированного в блоке catch для получения более детальной информации об исключении, а именно само сообщение об ошибке, код ошибки (если такой имеется), файл и линия, где данное исключение было обработано.
Теперь в принципе вам должны быть ясны преимущества исключений. Обратите внимание на этот простой механизм, который может поможет вам отлавливать недочёты даже в самых “глубоких” местах. В добавок он даёт вам детальную информацию об ошибке, что позволит вам быстро всё исправить.
Вот ещё пример:
class Generic
{
private $someVar, $result;
const NUM_ERROR = 1;
const ANY_ERROR = 2;
public function __construct($someVar)
{
$this->someVar = $someVar;
}
public function testValue($someOtherVar)
{
if($someOtherVar > 3) {
throw new Exception('Значение параметра не божет быть больше 3!', self::NUM_ERROR);
} else {
$this->result = $this->someVar + $someOtherVar;
echo $this->result . '<br />';
}
}
public function otherMethod()
{
if($this->result > 4) {
throw new Exception('Результат больше 4.', self::ANY_ERROR);
}
}
}
// Начинаем охоту
try
{
$gen = new Generic(3);
$gen->testValue(2);
$gen->otherMethod();
} catch (Exception $e) {
if($e->getCode() == 1) {
die ($e->getMessage());
} else {
echo 'Error :' . $e->getMessage() . '<br />';
echo 'File :' . $e->getFile() . '<br />';
echo 'Line :' . $e->getLine() . '<br />';
exit();
}
}
В этом новом примере я использую более сложную систему перехвата исключительных ситуаций, которые будут вызываться в зависимости от второго параметра, используемого в блоке CATCH. Это позволит вам создать систему ещё гибче в зависимости от выбрасываемого типа исключения.
Но это ещё не всё, что вы можете делать. Вы так же можете создавать свои типы исключений. В этом нет ничего сложного. Нам нужно просто создать дополнительный класс, который будет наследовать класс exception.
Кроме унаследованных методов, вы так же можете добавить и свои. Вот пример:
class Generic
{
private $someVar, $result;
const NUM_ERROR = 1;
const ANY_ERROR = 2;
public function __construct($someVar)
{
$this->someVar = $someVar;
}
public function testValue($someOtherVar)
{
if($someOtherVar > 3) {
throw new CustomException('Значение параметра не божет быть больше 3!', self::NUM_ERROR);
} else {
$this->result = $this->someVar + $someOtherVar;
echo $this->result . '<br />';
}
}
public function otherMethod()
{
if($this->result > 4) {
throw new CustomException('Результат больше 4.', self::ANY_ERROR);
}
}
}
class CustomException extends Exception
{
public function logError()
{
// Записать в логи сервера
if($this->getCode() == Generic::NUM_ERROR){
error_log($this->getMessage(), 0);
}
// Сообщить админу по email
else if($this->getCode() == Generic::ANY_ERROR){
error_log($this->getMessage(), 1, 'sysadmin@domain.com');
}
}
}
// Отлавливаем
try
{
$gen = new Generic(3);
$gen->testValue(2);
$gen->otherMethod();
} catch (CustomException $e) {
$e->logError();
}
В этом примере мы создали наш собственный тип исключения CustomException.
При вызове logError() в зависимости от типа ошибки, будет осуществляться соответствующее действие (запись в логи или письмо админу).
В PHP5 существует метод set_exception_handler, который позволяет определить функцию перехватывающую все не отловленные исключения.
function myException($exception)
{
echo "<strong>Exception:</strong> " , $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Новое исключение');
PHP исключения это очень важный аспект, который должен использоваться в каждом крупном проекте. Многие PHP фрэймворки используют данную технику для регистрации всех ошибок, что позволяет быстро их устранить, тем самым строить настолько безопасные системы насколько это возможно.