Files
archived-doc-pt-br/language/exceptions.xml
Leonardo Lara Rodrigues 3ee3071c6c fix and improve translations
2025-09-29 11:40:16 -03:00

604 lines
17 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: c81a48e58fc530a74827316027fae74668d17a1d Maintainer: leonardolara Status: ready --><!-- CREDITS: narigone,felipe,ae,geekcom,leonardolara -->
<chapter xml:id="language.exceptions" xmlns="http://docbook.org/ns/docbook">
<title>Exceções</title>
<para>
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.
</para>
<para>
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 blocos &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.
</para>
<para>
O objeto lançado precisa ser uma &instanceof; <interfacename>Throwable</interfacename>.
Tentar lançar um objeto sem essa ascendência resultará em um erro fatal.
</para>
<para>
A partir do PHP 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.
</para>
<sect1 annotations="chunk:false" xml:id="language.exceptions.catch">
<title><literal>catch</literal></title>
<para>
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.
</para>
<para>
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 bloco &catch; que foi acionado.
</para>
<para>
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
"<literal>Uncaught Exception ...</literal>" na ausência de uma função
definida com <function>set_exception_handler</function>.
</para>
<para>
A partir do PHP 7.1 um bloco &catch; pode especificar múltiplas exceções
usando o caractere pipe (<literal>|</literal>). Isto é útil quando
diferentes exceções de diferentes hierarquias de classes são tratadas
da mesma forma.
</para>
<para>
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.
</para>
</sect1>
<sect1 annotations="chunk:false" xml:id="language.exceptions.finally">
<title><literal>finally</literal></title>
<para>
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.
</para>
<para>
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.
</para>
<para>
Outra interação notável é entre uma exceção lançada de dentro de um bloco &try;
e uma lançada de dentro de um bloco &finally;. Se ambos os blocos lançarem uma exceção,
a que for lançada de dentro do bloco &finally; será a propagada,
e a lançada de dentro do bloco &try; será usada como sua exceção anterior.
</para>
</sect1>
<sect1 annotations="chunk:false" xml:id="language.exceptions.exception-handler">
<title>Manipulador de exceções global</title>
<para>
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 <function>set_exception_handler</function>
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;.
</para>
</sect1>
<sect1 annotations="chunk:false" xml:id="language.exceptions.notes">
&reftitle.notes;
<note>
<para>
Funções internas ao PHP utilizam principalmente
<link linkend="ini.error-reporting">aviso de erros</link>. Apenas extensões
<link linkend="language.oop5">orientadas a objetos</link>
utilizam exceções. No entanto, os erros podem ser transformados em
exceções com <link linkend="class.errorexception">ErrorException</link>.
Essa técnica não funciona para erros fatais.
</para>
<example>
<title>Convertendo avisos de erros em exceções</title>
<programlisting role="php">
<![CDATA[
<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler('exceptions_error_handler');
?>
]]>
</programlisting>
</example>
</note>
<tip>
<para>
A <link linkend="intro.spl">biblioteca padrão do PHP (SPL)</link> fornece
várias <link linkend="spl.exceptions">exceções
nativas</link>.
</para>
</tip>
</sect1>
<sect1 annotations="chunk:false" xml:id="language.exceptions.examples">
&reftitle.examples;
<example>
<title>Lançando uma exceção</title>
<programlisting role="php">
<![CDATA[
<?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";
}
// A execução continua
echo "Olá mundo\n";
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
0.2
Exceção capturada: Divisão por zero.
Olá mundo
]]>
</screen>
</example>
<example>
<title>Manipulação de exceções com bloco &finally;</title>
<programlisting role="php">
<![CDATA[
<?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";
}
// A execução continua
echo "Olá mundo\n";
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
0.2
Primeiro finally.
Exceção capturada: Divisão por zero.
Segundo finally.
Olá mundo
]]>
</screen>
</example>
<example>
<title>Interação entre blocos &finally; e &return;</title>
<programlisting role="php">
<![CDATA[
<?php
function test() {
try {
throw new Exception('foo');
} catch (Exception $e) {
return 'catch';
} finally {
return 'finally';
}
}
echo test();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
finally
]]>
</screen>
</example>
<example>
<title>Exceção aninhada</title>
<programlisting role="php">
<![CDATA[
<?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();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
string(4) "foo!"
]]>
</screen>
</example>
<example>
<title>Manipulação de múltiplas exceções no mesmo bloco catch</title>
<programlisting role="php">
<![CDATA[
<?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();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
string(11) "MyException"
]]>
</screen>
</example>
<example>
<title>Omissão da variável de captura de exceções</title>
<para>Permitido a partir do PHP 8.0.0.</para>
<programlisting role="php">
<![CDATA[
<?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.";
}
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Uma exceção SpecificException foi lançada, mas os detalhes não importam.
]]>
</screen>
</example>
<example>
<title>Throw como uma expressão</title>
<para>Permitido apenas no PHP 8.0.0 e posteriores.</para>
<programlisting role="php">
<![CDATA[
<?php
function test() {
do_something_risky() or throw new Exception('Não funcionou');
}
function do_something_risky() {
return false; // Simula falha
}
try {
test();
} catch (Exception $e) {
print $e->getMessage();
}
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Não funcionou
]]>
</screen>
</example>
<example>
<title>Exceção em bloco try e bloco finally</title>
<programlisting role="php">
<![CDATA[
<?php
try {
try {
throw new Exception(message: 'Terceira', previous: new Exception('Quarta'));
} finally {
throw new Exception(message: 'Primeira', previous: new Exception('Segunda'));
}
} catch (Exception $e) {
var_dump(
$e->getMessage(),
$e->getPrevious()->getMessage(),
$e->getPrevious()->getPrevious()->getMessage(),
$e->getPrevious()->getPrevious()->getPrevious()->getMessage(),
);
}
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
string(5) "Primeira"
string(6) "Segunda"
string(5) "Terceira"
string(6) "Quarta"
]]>
</screen>
</example>
</sect1>
<sect1 xml:id="language.exceptions.extending">
<title>Estendendo exceções</title>
<para>
Uma classe de exceção definida pelo usuário pode ser criada herdando a classe
Exception. Os membros e propriedades abaixo mostram o que é acessível
a partir da classe filha que deriva da Exception.
</para>
<example>
<title>A classe nativa Exception</title>
<programlisting role="php">
<![CDATA[
<?php
class Exception implements Throwable
{
protected $message = 'Unknown exception'; // Mensagem da exceção
private $string; // Cache __toString
protected $code = 0; // Código definido pelo usuário
protected $file; // Nome do arquivo onde a exceção originou
protected $line; // Número da linha onde a exceção originou
private $trace; // Backtrace
private $previous; // Exceção anterior (se exceção empilhada)
public function __construct($message = '', $code = 0, ?Throwable $previous = null);
final private function __clone(); // Inibe a clonagem de exceções
final public function getMessage(); // Mensagem da exceção
final public function getCode(); // Código definido pelo usuário
final public function getFile(); // Nome do arquivo onde a exceção originou
final public function getLine(); // Número da linha onde a exceção originou
final public function getTrace(); // Um array do backtrace()
final public function getPrevious(); // Exceção anterior
final public function getTraceAsString(); // Backtrace formatado como string
// Pode ser sobrescrito
public function __toString(); // String formatada da exceção
}
?>
]]>
</programlisting>
</example>
<para>
Se uma classe estender a classe Exception e redefinir o <link
linkend="language.oop5.decon">construtor</link>, então é altamente recomendável
que também seja chamado o <link
linkend="language.oop5.paamayim-nekudotayim">parent::__construct()</link>
para garantir que todos os dados estejam corretamente informados. O método <link
linkend="language.oop5.magic">__toString()</link> pode ser sobrescrito
para fornecer uma representação customizada do objeto quando utilizado como string.
</para>
<note>
<para>
Exceções não podem ser clonadas. Tentativas de <link
linkend="language.oop5.cloning">clonar</link> um Exception resultarão em
erros <constant>E_ERROR</constant> fatais.
</para>
</note>
<example>
<title>Estendendo a classe Exception</title>
<programlisting role="php">
<![CDATA[
<?php
/**
* Define uma classe de exceção
*/
class MyException extends Exception
{
// Redefine a exceção de forma que a mensagem não seja opcional
public function __construct($message, $code = 0, ?Throwable $previous = null) {
// código
// garante que tudo está corretamente inicializado
parent::__construct($message, $code, $previous);
}
// Personaliza a apresentação do objeto como string
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function customFunction() {
echo "Uma função específica desse tipo de exceção\n";
}
}
/**
* Cria uma classe para testar a exceção
*/
class TestException
{
public $var;
const THROW_NONE = 0;
const THROW_CUSTOM = 1;
const THROW_DEFAULT = 2;
function __construct($avalue = self::THROW_NONE) {
switch ($avalue) {
case self::THROW_CUSTOM:
// lança a exceção customizada
throw new MyException('1 é um parâmetro inválido', 5);
break;
case self::THROW_DEFAULT:
// throw default one.
throw new Exception('2 não é um parâmetro permitido', 6);
break;
default:
// Sem exceção, o objeto será criado
$this->var = $avalue;
break;
}
}
}
// Exemplo 1
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (MyException $e) { // Entrará aqui ...
echo "Pegou MyException\n", $e;
$e->customFunction();
} catch (Exception $e) { // ... mas não aqui.
echo "Pegou Exception padrão\n", $e;
}
// A execução continua
var_dump($o); // Null
echo "\n\n";
// Exemplo 2
try {
$o = new TestException(TestException::THROW_DEFAULT);
} catch (MyException $e) { // Não entrará aqui ...
echo "Pegou MyException\n", $e;
$e->customFunction();
} catch (Exception $e) { // ... porque entrará aqui.
echo "Pegou Exception padrão\n", $e;
}
// A execução continua
var_dump($o); // Null
echo "\n\n";
// Exemplo 3
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (Exception $e) { // Entrará aqui
echo "Pegou exceção padrão\n", $e;
}
// A execução continua
var_dump($o); // Null
echo "\n\n";
// Exemplo 4
try {
$o = new TestException();
} catch (Exception $e) { // Não entrará, sem exceção
echo "Pegou Exception padrão\n", $e;
}
// A execução continua
var_dump($o); // TestException
echo "\n\n";
?>
]]>
</programlisting>
</example>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->