Exceções

Table of Contents

O PHP possui um modelo de exceções similar ao de outras linguagens de programação. Uma exceção pode ser lançada (throw) e capturada (catch). Código pode ser envolvido por um bloco try para facilitar a captura de exceções potenciais. Cada bloco try precisa ter ao menos um bloco catch ou finally correspondente.

Se uma exceção é lançada e o escopo atual não possui nenhum block catch, a exceção irá "desempilhar" o call stack pelas funções chamadoras até encontrar um bloco catch compatível. Todos os blocks finally encontrados pelo caminho serão executados. Se a pilha é esvaziada até o escopo global sem encontrar um block catch compatível, o programa irá terminar com um erro fatal a não ser que um manipulador global de exceções tenha sido configurado.

O objeto lançado precisa ser uma instanceof Throwable. Tentar lançar um objeto sem essa ascendência resultará em um erro fatal.

A partir doPHP 8.0.0, a palavra chave throw é uma expressão e pode ser utilizada em qualquer contexto de expressão. Em versões anteriores era considerado uma instrução e portanto precisava constar em sua própria linha.

catch

Um bloco catch define como o código responde a uma exceção lançada. Um bloco catch define um ou mais tipos de exceções ou erros que ele pode processar, e opcionalmente uma variável para receber a exceção lançada. (A variável era requerida anteriormente ao PHP 8.0.0.) O primeiro bloco catch que uma exceção ou erro lançados encontram que seja compatível com o tipo objeto lançado irá processar esse objeto.

Múltiplos blocos catch podem ser utilizados para capturar exceções diferentes. A execução normal (quando nenhuma exceção é lançada dentro de um try) irão continuar a execução após o último catch definido em sequência. Exceções podem ser lançadas ou relançadas (throw) dentro um bloco catch. Caso contrário, a execução irá continuar após o blococatch que foi acionado.

Quando uma exceção é lançada o código seguinte não é executado, e o PHP tentará encontrar o primeiro bloco catch coincidente. Se uma exceção não for capturada, um erro PHP fatal será lançado com a mensagem "Uncaught Exception ..." na ausência de uma função definida com set_exception_handler().

A partir do PHP 7.1 um bloco catch pode especificar múltiplas exceções usando o caractere pipe (|). Isto é útil quando diferentes exceções de diferentes hierarquias de classes são tratadas da mesma forma.

A partir do PHP 8.0.0, o nome de variável que captura a exceção é opcional. Se não especificada, o bloco catch compatível ainda executará, mas não terá acesso ao objeto lançado.

finally

Um bloco finally pode ser especificado após ou no lugar de blocos catch. Códigos dentro de finally sempre serão executados depois do try ou catch, independente se houve o lançamento de uma exceção, e antes que a execução normal continue.

Uma interação notável ocorre entre um bloco finally e a instrução return. Se uma instrução return é encontrada dentro um bloco try ou catch, o bloco finally ainda assim será executado. Além disso a instrução return é avaliada no ponto que é encontrada, mas o resultado só será retornado após o bloco finally ser executado. Se o bloco finally também tiver uma instrução return, o valor da instrução de finally que será retornado.

Manipulador de exceções global

Se uma exceção alcança o escopo global, ela ainda pode ser capturada por um manipulador global de exceções, opcional. A função set_exception_handler() pode configurar uma função que será chamada no lugar de um bloco catch na ausẽncia de outros blocos. O efeito é essencialmente o mesmo que ter o programa inteiro envelopado dentro de um bloco try-catch e a função informada funcionando como o catch.

Notas

Note:

Funções internas ao PHP utilizam principalmente aviso de erros. Apenas extensões orientadas a objetos utilizam exceções. No entanto os erros podem ser transformados em exceções com ErrorException. Essa técnica não funciona para erros fatais.

Example #1 Convertendo avisos de erros em exceções

<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
    throw new ErrorException($message, 0, $severity, $filename, $lineno);
}

set_error_handler('exceptions_error_handler');
?>

Exemplos

Example #2 Lançando uma exceção

<?php
function inverse($x) {
    if (!$x) {
        throw new Exception('Divisão por zero.');
    }
    return 1/$x;
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'Exceção capturada: ',  $e->getMessage(), "\n";
}

// Execução continua
echo "Olá mundo\n";
?>

O exemplo acima produzirá:

0.2
Exceção capturada: Divisão por zero.
Olá mundo

Example #3 Manipulação de exceções com bloco finally

<?php
function inverse($x) {
    if (!$x) {
        throw new Exception('Divisão por zero.');
    }
    return 1/$x;
}

try {
    echo inverse(5) . "\n";
} catch (Exception $e) {
    echo 'Exceção capturada: ',  $e->getMessage(), "\n";
} finally {
    echo "Primeiro finaly.\n";
}

try {
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'Exceção capturada: ',  $e->getMessage(), "\n";
} finally {
    echo "Segundo finally.\n";
}

// Execução continua
echo "Olá mundo\n";
?>

O exemplo acima produzirá:

0.2
Primeiro finally.
Exceção capturada: Divisão por zero.
Segundo finally.
Olá mundo

Example #4 Interação entre blocos finally e return

<?php

function test() {
    try {
        throw new Exception('foo');
    } catch (Exception $e) {
        return 'catch';
    } finally {
        return 'finally';
    }
}

echo test();
?>

O exemplo acima produzirá:

finally

Example #5 Exceções alinhadas

<?php

class MyException extends Exception { }

class Test {
    public function testing() {
        try {
            try {
                throw new MyException('foo!');
            } catch (MyException $e) {
                // rethrow it
                throw $e;
            }
        } catch (Exception $e) {
            var_dump($e->getMessage());
        }
    }
}

$foo = new Test;
$foo->testing();

?>

O exemplo acima produzirá:

string(4) "foo!"

Example #6 Manipulação de múltiplas exceções no mesmo bloco catch

<?php

class MyException extends Exception { }

class MyOtherException extends Exception { }

class Test {
    public function testing() {
        try {
            throw new MyException();
        } catch (MyException | MyOtherException $e) {
            var_dump(get_class($e));
        }
    }
}

$foo = new Test;
$foo->testing();

?>

O exemplo acima produzirá:

string(11) "MyException"

Example #7 Omissão da variável de captura de exceções

Permitido a partir do PHP 8.0.0.

<?php

class SpecificException extends Exception {}

function test() {
    throw new SpecificException('Oopsie');
}

try {
    test();
} catch (SpecificException) {
    print "Uma exceção SpecificException foi lançada, mas os detalhes não importam.";
}
?>

Example #8 Throw as an expression

Only permitted in PHP 8.0.0 and later.

<?php

function test() {
    do_something_risky() or throw new Exception('It did not work');
}

try {
    test();
} catch (Exception $e) {
    print $e->getMessage();
}
?>