Ответ 1
Вы не должны ловить исключение, если вы не намерены делать что-то значимое.
"Что-то значимое" может быть одним из следующих:
Обработка исключения
Наиболее очевидным значимым действием является обработка исключения, например. путем отображения сообщения об ошибке и отмены операции:
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();
}
и в результате поймать ошибку "Целевая директория не может быть создана", вы имели бы право путаться. Обтекание этого "основного" исключения в слоях других исключений, обеспечивающих контекст, облегчит обработку ошибки ( "Ошибка создания профиля" → "Не удалось выполнить операцию копирования файлов" → "Целевой каталог не может быть создан" ).