W3docs

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 loaded

O 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

  • try precisa de um parceiro. Um bloco try sozinho não será analisado — combine-o com pelo menos um catch ou um finally.
  • 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, portanto catch não os verá. Use set_error_handler() ou verifique os valores de retorno para esses casos. Objetos Error fatais (como TypeError) podem ser capturados porque implementam Throwable.
  • Ordene seus blocos catch do mais específico ao mais geral. Um catch (Exception $e) amplo colocado primeiro oculta todos os blocos subsequentes.
  • Não engula silenciosamente. Um bloco catch vazio oculta a falha; no mínimo registre $e->getMessage() para que o problema seja visível.
  • finally pode mascarar exceções. Retornar de finally descarta tanto o valor de retorno do try quanto 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

Prática

Prática
Qual tag é usada em PHP para iniciar um bloco de código?
Qual tag é usada em PHP para iniciar um bloco de código?
Was this page helpful?