Вы не должны ловить исключение, если не собираетесь делать что-то значимое .
«Что-то значимое» может быть одним из следующих:
Обработка исключения
Наиболее очевидным значимым действием является обработка исключения, например, путем отображения сообщения об ошибке и отмены операции:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
echo "Error while connecting to database!";
die;
}
Ведение журнала или частичная очистка
Иногда вы не знаете, как правильно обрабатывать исключения в определенном контексте; возможно, вам не хватает информации о «общей картине», но вы хотите записать сбой как можно ближе к точке, где это произошло. В этом случае вы можете поймать, зарегистрировать и перебросить:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
logException($e); // does something
throw $e;
}
Связанный сценарий - это то, где вы находитесь в правильном месте, чтобы выполнить некоторую очистку для неудачной операции, но не решить, как следует обрабатывать сбой на верхнем уровне. В более ранних версиях PHP это было бы реализовано как
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
catch (Exception $e) {
$connect->disconnect(); // we don't want to keep the connection open anymore
throw $e; // but we also don't know how to respond to the failure
}
В PHP 5.5 введено finally
ключевое слово, поэтому для сценариев очистки теперь есть другой способ приблизиться к этому. Если код очистки должен выполняться независимо от того, что произошло (т. Е. Как при ошибке, так и при успехе), теперь это можно сделать, прозрачно разрешая распространяться любым сгенерированным исключениям:
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
finally {
$connect->disconnect(); // no matter what
}
Ошибка абстракции (за исключением цепочки)
Третий случай - когда вы хотите логически сгруппировать множество возможных сбоев под большим зонтиком. Пример для логической группировки:
class ComponentInitException extends Exception {
// public constructors etc as in Exception
}
class Component {
public function __construct() {
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
throw new ComponentInitException($e->getMessage(), $e->getCode(), $e);
}
}
}
В этом случае вы не хотите, чтобы пользователи Component
знали, что это реализовано с использованием соединения с базой данных (возможно, вы хотите оставить свои параметры открытыми и использовать файловое хранилище в будущем). Таким образом, в вашей спецификации Component
будет сказано, что «в случае сбоя инициализации ComponentInitException
будет выброшено». Это позволяет потребителям Component
ловить исключения ожидаемого типа, а также позволяет отладочному коду получать доступ ко всем (зависящим от реализации) деталям .
Обеспечение более богатого контекста (за исключением цепочки)
Наконец, есть случаи, когда вы можете предоставить больше контекста для исключения. В этом случае имеет смысл заключить исключение в другое, которое содержит больше информации о том, что вы пытались сделать, когда произошла ошибка. Например:
class FileOperation {
public static function copyFiles() {
try {
$copier = new FileCopier(); // the constructor may throw
// this may throw if the files do no not exist
$copier->ensureSourceFilesExist();
// this may throw if the directory cannot be created
$copier->createTargetDirectory();
// this may throw if copying a file fails
$copier->performCopy();
}
catch (Exception $e) {
throw new Exception("Could not perform copy operation.", 0, $e);
}
}
}
Этот случай аналогичен приведенному выше (и пример, вероятно, не самый лучший, который можно придумать), но он иллюстрирует смысл предоставления большего контекста: если выдается исключение, он говорит нам, что копирование файла завершилось неудачно. Но почему это не удалось? Эта информация предоставляется в обернутых исключениях (которых может быть более одного уровня, если пример был намного сложнее).
Значение этого показано на примере сценария, в котором, например, создание UserProfile
объекта приводит к копированию файлов, поскольку профиль пользователя хранится в файлах и поддерживает семантику транзакций: вы можете «отменить» изменения, потому что они выполняются только на Копия профиля, пока вы не совершите.
В этом случае, если вы сделали
try {
$profile = UserProfile::getInstance();
}
и в результате возникнет ошибка исключения «Целевой каталог не может быть создан», вы будете иметь право на путаницу. Обтекание этого «основного» исключения слоями других исключений, которые предоставляют контекст, значительно упростит обработку ошибки («Ошибка создания копии профиля» -> «Ошибка операции копирования файла» -> «Не удалось создать целевой каталог»).