mirror of
https://github.com/php/doc-pt_br.git
synced 2026-03-24 07:02:09 +01:00
604 lines
17 KiB
XML
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
|
|
-->
|