Você não deve capturar a exceção, a menos que pretenda fazer algo significativo .
"Algo significativo" pode ser um dos seguintes:
Manipulando a exceção
A ação significativa mais óbvia é lidar com a exceção, por exemplo, exibindo uma mensagem de erro e interrompendo a operação:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
echo "Error while connecting to database!";
die;
}
Log ou limpeza parcial
Às vezes, você não sabe como lidar adequadamente com uma exceção dentro de um contexto específico; talvez você não tenha informações sobre o "quadro geral", mas deseja registrar a falha o mais próximo possível do possível. Nesse caso, convém capturar, registrar e lançar novamente:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
logException($e); // does something
throw $e;
}
Um cenário relacionado é onde você está no lugar certo para executar uma limpeza na operação com falha, mas não para decidir como a falha deve ser tratada no nível superior. Nas versões anteriores do PHP, isso seria implementado como
$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
}
O PHP 5.5 introduziu a finally
palavra - chave, portanto, para cenários de limpeza, agora existe outra maneira de abordar isso. Se o código de limpeza precisar executar, não importa o que aconteceu (por exemplo, com erro e com êxito), agora é possível fazer isso, permitindo com transparência a propagação de qualquer exceção lançada:
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
finally {
$connect->disconnect(); // no matter what
}
Abstração de erro (com encadeamento de exceção)
Um terceiro caso é onde você deseja agrupar logicamente muitas possíveis falhas sob um guarda-chuva maior. Um exemplo para agrupamento lógico:
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);
}
}
}
Nesse caso, você não deseja que os usuários Component
saibam que ela é implementada usando uma conexão com o banco de dados (talvez você queira manter suas opções abertas e usar o armazenamento baseado em arquivo no futuro). Portanto, sua especificação Component
diria que "no caso de uma falha de inicialização, ComponentInitException
será lançada". Isso permite que os consumidores Component
capturem exceções do tipo esperado , além de permitir que o código de depuração acesse todos os detalhes (dependentes da implementação) .
Fornecendo um contexto mais rico (com encadeamento de exceção)
Finalmente, há casos em que você pode fornecer mais contexto para a exceção. Nesse caso, faz sentido agrupar a exceção em outra que contém mais informações sobre o que você estava tentando fazer quando ocorreu o erro. Por exemplo:
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);
}
}
}
Este caso é semelhante ao acima (e o exemplo provavelmente não é o melhor possível), mas ilustra o ponto de fornecer mais contexto: se uma exceção for lançada, ele nos informa que a cópia do arquivo falhou. Mas por que falhou? Essas informações são fornecidas nas exceções agrupadas (das quais poderia haver mais de um nível, se o exemplo fosse muito mais complicado).
O valor de fazer isso é ilustrado se você pensar em um cenário em que, por exemplo, a criação de um UserProfile
objeto faz com que os arquivos sejam copiados porque o perfil do usuário é armazenado em arquivos e suporta a semântica de transações: você pode "desfazer" as alterações porque elas são executadas apenas em um ambiente. cópia do perfil até você confirmar.
Nesse caso, se você fez
try {
$profile = UserProfile::getInstance();
}
e, como resultado, ocorreu um erro de exceção "O diretório de destino não pôde ser criado", você teria o direito de ficar confuso. O agrupamento dessa exceção "principal" em camadas de outras exceções que fornecem contexto tornará o erro muito mais fácil de lidar ("Falha na criação da cópia do perfil" -> "Falha na operação de cópia do arquivo" -> "O diretório de destino não pôde ser criado").
finally
construção (pelo menos ainda não) ... Então, isso é fora, o que significa que temos de recorrer a coisas sujas como este ...finally
no PHP.error_code
propriedade que pode ser verificada para obter o erro subjacente código. Se você conseguir lidar com alguns desses erros de maneira significativa, provavelmente desejará capturar, inspecionar e, se não conseguir lidar com o erro, repita o processo.Bem, é tudo sobre manter a abstração. Então, eu sugiro usar o encadeamento de exceção para jogar diretamente. Quanto ao motivo, deixe-me explicar o conceito de abstrações com vazamentos
Digamos que você esteja construindo um modelo. O modelo deve abstrair toda a persistência e validação de dados do restante do aplicativo. Então agora o que acontece quando você recebe um erro no banco de dados? Se você repetir a exibição
DatabaseQueryException
, estará vazando a abstração. Para entender o porquê, pense na abstração por um segundo. Você não se importa como o modelo armazena os dados, apenas o faz. Da mesma forma, você não se importa exatamente com o que deu errado nos sistemas subjacentes do modelo, apenas que você sabe que algo deu errado e aproximadamente o que deu errado.Então, ao reler o DatabaseQueryException, você está perdendo a abstração e exigindo que o código de chamada entenda a semântica do que está acontecendo no modelo. Em vez disso, crie um genérico
ModelStorageException
e envolva o que estáDatabaseQueryException
dentro dele. Dessa forma, seu código de chamada ainda pode tentar lidar com o erro semântica, mas não importa a tecnologia subjacente do Modelo, pois você está apenas expondo erros dessa camada de abstração. Ainda melhor, desde que você quebrou a exceção, se ela borbulhar totalmente e precisar ser registrada, você poderá rastrear a exceção raiz lançada (percorrer a cadeia) para ainda ter todas as informações de depuração necessárias!Não basta capturar e repetir a mesma exceção, a menos que precise fazer algum pós-processamento. Mas um bloco como
} catch (Exception $e) { throw $e; }
é inútil. Mas você pode refazer as exceções para obter algum ganho significativo de abstração.fonte
IMHO, capturando uma exceção para apenas relançá-la é inútil . Nesse caso, apenas não o pegue e deixe que os métodos chamados anteriormente o tratem (também conhecidos como métodos que são 'superiores' na pilha de chamadas) .
Se você repetir a reprodução, encadear a exceção capturada para a nova que você lançará é definitivamente uma boa prática, pois manterá as informações que a exceção capturada contém. No entanto, relançar é útil apenas se você adicionar alguma informação ou manipular algo à exceção capturada, seja algum contexto, valores, registro, liberação de recursos, o que for.
Uma maneira de adicionar algumas informações é estender a
Exception
classe, para ter exceções, comoNullParameterException
,DatabaseException
, etc. Mais ainda, esta permitir que o developper apenas para pegar algumas exceções que ele pode manipular. Por exemplo, é possível capturar apenasDatabaseException
e tentar resolver o que causou oException
, como se reconectar ao banco de dados.fonte
Você deve dar uma olhada nas práticas recomendadas de exceção no PHP 5.3
O tratamento de exceções no PHP não é um recurso novo em nenhum momento. No link a seguir, você verá dois novos recursos no PHP 5.3, baseados em exceções. O primeiro são exceções aninhadas e o segundo é um novo conjunto de tipos de exceção oferecidos pela extensão SPL (que agora é uma extensão principal do tempo de execução do PHP). Esses dois novos recursos foram incluídos no livro de melhores práticas e merecem ser examinados em detalhes.
http://ralphschindler.com/2010/09/15/exception-best-practices-in-php-5-3
fonte
Você costuma pensar dessa maneira.
Uma classe pode lançar muitos tipos de exceções que não corresponderão. Então você cria uma classe de exceção para essa classe ou tipo de classe e lança isso.
Portanto, o código que usa a classe precisa capturar apenas um tipo de exceção.
fonte