try
Aprenda como o PHP try/catch/finally trata exceções. Abrange múltiplos blocos catch, tipos union, relançamento e armadilhas comuns.
A Palavra-chave try do PHP
A palavra-chave try marca um bloco de código que pode lançar uma exceção — um objeto que sinaliza que algo deu errado e a execução normal não pode continuar. Quando uma exceção é lançada dentro de um bloco try, o PHP para de executar o restante desse bloco e procura um bloco catch correspondente para tratá-la. Um bloco finally opcional é então executado independentemente do que aconteceu.
Esta página aborda a sintaxe try/catch/finally, como múltiplos blocos catch são correspondidos, como capturar vários tipos de exceção de uma vez, o relançamento e as armadilhas que costumam pegar as pessoas de surpresa. Se você é novo na ideia de lançar erros, leia Exceções em PHP primeiro.
Sintaxe
try {
// Code that may throw an exception
} catch (ExceptionType $e) {
// Code that runs if an exception of ExceptionType (or a subclass) is thrown
} finally {
// Optional: always runs, whether or not an exception was thrown
}Um bloco try deve ser seguido por pelo menos um bloco catch, ou um bloco finally, ou ambos — um try sozinho é um erro de sintaxe. A variável em catch (ExceptionType $e) armazena o objeto de exceção lançado, que você consulta com métodos como $e->getMessage().
Um primeiro exemplo
A função abaixo lança uma exceção quando solicitada a dividir por zero. O bloco try a chama, o bloco catch reporta o problema e finally sempre é executado:
<?php
function divide($dividend, $divisor)
{
if ($divisor == 0) {
throw new Exception("Cannot divide by zero.");
}
return $dividend / $divisor;
}
try {
$result = divide(10, 0);
echo $result; // skipped — divide() threw before returning
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . PHP_EOL;
} finally {
echo "Done." . PHP_EOL;
}Saída:
Error: Cannot divide by zero.
Done.Observe que echo $result; nunca é executado: uma vez que divide(10, 0) lança uma exceção, o controle passa diretamente para o bloco catch. O bloco finally é executado depois. Se você chamar divide(10, 2) em vez disso, nenhuma exceção é lançada, o bloco try imprime 5 e finally ainda imprime Done..
Múltiplos blocos catch
Um único try pode ser seguido por vários blocos catch. O PHP os verifica de cima para baixo e executa o primeiro cujo tipo corresponda à exceção lançada (a correspondência inclui subclasses). Liste os tipos mais específicos antes dos mais gerais — um catch (Exception $e) no início engolirá tudo abaixo dele.
<?php
try {
$value = "5";
if (!is_int($value)) {
throw new TypeError("Expected an integer.");
}
} catch (TypeError $e) {
echo "Type problem: " . $e->getMessage() . PHP_EOL;
} catch (Exception $e) {
echo "Other problem: " . $e->getMessage() . PHP_EOL;
}Saída:
Type problem: Expected an integer.Capturando vários tipos em um único bloco
Quando dois tipos de exceção devem ser tratados da mesma forma, combine-os com uma barra vertical (|) — um recurso adicionado no PHP 7.1 — em vez de duplicar o bloco:
<?php
try {
throw new RuntimeException("Network timed out.");
} catch (RuntimeException | LogicException $e) {
echo "Handled: " . $e->getMessage() . PHP_EOL;
}Saída:
Handled: Network timed out.Como o finally se comporta
O bloco finally é executado mesmo que o bloco try ou catch execute um return. Isso o torna o lugar certo para limpeza — fechar arquivos, liberar bloqueios, reverter uma transação — que deve ocorrer em todos os caminhos:
<?php
function readConfig()
{
try {
return "config loaded";
} finally {
echo "Cleanup ran." . PHP_EOL;
}
}
echo readConfig() . PHP_EOL;Saída:
Cleanup ran.
config loadedO bloco finally é executado antes de a função retornar de fato seu valor. Evite retornar do próprio finally: um return lá substitui o valor de try/catch e descarta silenciosamente qualquer exceção que estava sendo lançada.
Relançando uma exceção
Um bloco catch pode fazer trabalho parcial — registrar o erro, adicionar contexto — e então relançar para que um chamador acima possa decidir o que fazer. Use throw $e; para relançar o mesmo objeto:
<?php
try {
try {
throw new Exception("Disk full.");
} catch (Exception $e) {
echo "Logging: " . $e->getMessage() . PHP_EOL;
throw $e; // hand it to the outer handler
}
} catch (Exception $e) {
echo "Outer handler: " . $e->getMessage() . PHP_EOL;
}Saída:
Logging: Disk full.
Outer handler: Disk full.Armadilhas comuns
tryprecisa de um parceiro. Um blocotrysozinho não será analisado — combine-o com pelo menos umcatchou umfinally.- Erros não são todos exceções. Muitos avisos de tempo de execução (uma variável indefinida, um
fopen()que falhou) não são lançados como exceções, portantocatchnão os verá. Useset_error_handler()ou verifique os valores de retorno para esses casos. ObjetosErrorfatais (comoTypeError) podem ser capturados porque implementamThrowable. - Ordene seus blocos
catchdo mais específico ao mais geral. Umcatch (Exception $e)amplo colocado primeiro oculta todos os blocos subsequentes. - Não engula silenciosamente. Um bloco
catchvazio oculta a falha; no mínimo registre$e->getMessage()para que o problema seja visível. finallypode mascarar exceções. Retornar definallydescarta tanto o valor de retorno dotryquanto qualquer exceção em andamento.
Quando devo usar try?
Use try/catch quando uma falha é excepcional e o código chamador pode reagir razoavelmente a ela: uma conexão com banco de dados que cai, uma API que retorna um erro, entrada de usuário inválida que você deseja rejeitar de forma limpa. Para fluxo de controle ordinário (uma chave foi encontrada em um array? uma string está vazia?), use condicionais normais — exceções são para o caminho anormal, não para ramificações do dia a dia.
Relacionados
catch— o bloco que trata uma exceção lançada.finally— código que sempre é executado apóstry/catch.throw— lance uma exceção você mesmo.- A classe Exception — o tipo base e seus métodos.
- Exceções em PHP — o panorama maior do tratamento de erros.
set_exception_handler()— capture exceções que escapam de todotry.