Исключения в приложении сайта Компания АВС

Мы уже знакомы с описанием, как данные заказа запчастей можно сохранить в двумерном (плоском) файле. Известно, что файловый ввод/вывод (фактически, любой вид ввода/вывода) — это та область программы, в которой часто возникают ошибки. Поэтому имеет смысл применить к нему механизм обработки исключений.

Если вернуться к исходному коду, можно заметить, что в процессе записи в файл могут возникнуть три проблемы: невозможность открытия файла, невозможность получения блокировки или невозможность записи в файл. Для каждой из этих ситуаций создадим класс исключения.

file_exceptions.php —исключения связанные с файловым вводом/выводом

<?php
class fileOpenException extends Exception
{
function __toString()
{
return 'fileOpenException '. $this -> getCode()
. ': '. $this -> getMessage(). '<br>'. 'в '
.$this -> getFile(). ', строка '. $this -> getLine()
.'<br>';
}
}
class fileWriteException extends Exception
{
function __toString()
{
return 'fileWriteException '. $this -> getCode()
. ': '. $this -> getMessage(). '<br>'. 'в '
.$this -> getFile(). ', строка '. $this -> getLine()
.'<br>';
}
}
class fileLockException extends Exception
{
function __toString()
{
return 'fileLockException '. $this -> getCode()
. ': '. $this -> getMessage(). '<br>'. 'в '
.$this -> getFile(). ', строка '. $this -> getLine()
.'<br>';
}
}
?>

Эти субклассы Exception не выполняют никаких действий, представляющих особый интерес. Фактически в этом приложении можно было бы оставить их пустыми или воспользоваться базовым классом Exception. Тем не менее, мы включили в каждый субкласс метод __toString(), который выводит сообщение о типе возникшего исключения.

Чтобы внедрить обработку исключений, перепишем файл processorder.php.

processorder.php —сценарий обработки заказов с добавленной в него обработкой исключений

<?php
require_once ('file_exception.php');
//создаем короткие имена переменным
$filtr = $_POST['filtr'];
$filtr_v = $_POST['filtr_v'];
$sparkqty = $_POST['sparkqty'];
$address = $_POST['address'];
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
//Объявляем константы
define ('FILTRPRICE', 20);
define ('FILTRVPRICE', 10);
define ('SPARKPRICE', 4);
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Компания АВС. Результаты заказа</title>
<link href="../../svd.css" rel="stylesheet" type="text/css">
</head>

<body class="text_blok" >
<h2>Компания АВС</h2>
<h3>Результаты заказа</h3>
<?php
$date = date('H:i, j F');
echo "<p>Заказ обработан в ";
echo $date;
echo "</p>";
echo "<p>Список вашего заказа:</p>";
$totalqty = 0;
$totalqty = $filtr + $filtr_v + $sparkqty;
echo 'Заказано товаров: '.$totalqty. '<br>';
if ($totalqty == 0)
{
echo '<font color=red>';
echo 'Вы ничего не заказали, повторите заказ!<br>';
echo '</font>';
}
else
{
if($filtr >0)
echo $filtr. " - фильтр масляный <br>";
if($filtr_v >0)
echo $filtr_v. " - фильтр воздушный<br>";
if($sparkqty >0)
echo $sparkqty. " - свечи зажигания <br>";
}
$totalamount = 0.00;
$totalamount = $filtr * FILTRPRICE
+ $filtr_v * FILTRVPRICE
+ $sparkqty * SPARKPRICE;
echo 'Итого: '.number_format($totalamount,2). ' RUB<br>';
$ndc = 0.18; //Налог НДС составляет 18%
$totalamount = $totalamount * (1 + $ndc);
echo 'Всего, включая НДС: '.$totalamount. ' RUB<br>';
echo 'Адрес доставки: '.$address. '<br>';
$outputstring = $date. "\t".$filtr. " фильтров масляных\t"
.$filtr_v. " фильтров воздушных\t"
.$sparkqty. " свечей зажигания \t" .$totalamount. " RUB\t" .$address. "\n";
//открыть файл для добавления
try
{
@ $fp = fopen ("$DOCUMENT_ROOT/phpstroy/test/orders.txt", 'ab');
if(!$fp)
throw new fileOpenException();

if(!flock ($fp, LOCK_EX)) //блокировка файла для записи
throw new fileLockException();

if(!fwrite ($fp, $outputstring, strlen($outputstring)))
throw new fileWriteException();
flock ($fp, LOCK_UN); //снятие блокировки
fclose($fp);
echo '<p>Заказ записан</p>';
}
catch (fileOpenException $foe)
{
echo '<p><strong>Невозможно открыть файл заказов</strong></p>';
}
catch (Exception $e)
{
echo '<p><strong>В настоящий момент ваш запрос не может быть обработан. '
.'Пожалуйста, попытайтесь позже. </strong></p></body></html>';
}
?>
</body>
</html>

Как видите, раздел кода сценария, реализующий файловый ввод/вывод, помещен в блок tru. В общем случае использование небольших блоков tru, в конце которых выполняется перехват важных исключений, считается правильным подходом к программированию. Это упрощает написание и сопровождение кода обработки исключений, поскольку легко понять, с чем приходится иметь дело.

В случае невозможности открытия файла код генерирует исключение fileOpenException. Невозможность блокирования файла ведет к генерированию исключения fileOpenException, а невозможности записи в файл — к генерированию исключения fileWriteException.

Взгляните на блоки catch. Для целей иллюстрации мы показали только два таких блока: один для обработки объектов fileOpenException и второй для обработки объектов Exception. Поскольку остальные исключения наследуют свойства и методы класса Exception, они будут перехватываться вторым блоком catch. Сопоставление блоков catch выполняется в соответствии с теми же основными правилами, что и применяемые в операторе instanceof. Это обстоятельство является вестким основанием для создания пользовательских классов исключений за счет расширения одного единственного класса.

Важное предупреждение: при генерировании исключения, для которого соответствующий блок catch не был создан, РНР сообщит о фатальной ошибке.

Исключения и другие механизмы обработки ошибок РНР

Помимо механизма обработки исключений, РНР обладает развитой поддержкой обработки ошибок. Важно отметить, что процесс генерирования и обработки исключений не влияет и не мешает работе данного механизма обработки ошибок.

Обратите внимание, что вызов метода fopen() предварен символом операции подавления ошибок (@). В случае неудачного выполнения этого метода, РНР генерирует предупреждение, вывод которого на экран или запись в журнал зависит от настроек отчета об ошибках, которые определены в файле php.ini. Следует знать, что данное предупреждение генерируется независимо от того, выполняется ли генерирование исключения.




  • Другие |
назадвверхвперед
Rambler's Top100