mirror of
https://github.com/php/doc-es.git
synced 2026-03-23 23:12:09 +01:00
613 lines
18 KiB
XML
613 lines
18 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- EN-Revision: c81a48e58fc530a74827316027fae74668d17a1d Maintainer: PhilDaiguille Status: ready -->
|
|
<!-- Reviewed: no -->
|
|
|
|
<chapter xml:id="language.exceptions">
|
|
<!-- we use our own DTD instead of xmlns="http://docbook.org/ns/docbook" so that we can use
|
|
<sect1 annotations="chunk:false"> -->
|
|
<title>Las excepciones</title>
|
|
<para>
|
|
PHP tiene un manejo de excepciones similar al que ofrecen otros
|
|
lenguajes de programación.
|
|
Una excepción puede ser lanzada ("&throw;") y capturada
|
|
("&catch;") en PHP. El código deberá estar rodeado
|
|
de un bloque &try; para facilitar la captura de una excepción
|
|
potencial. Cada &try; debe tener al menos
|
|
un bloque &catch; o &finally; correspondiente.
|
|
</para>
|
|
<para>
|
|
Si una excepción es lanzada y el ámbito actual de la función no tiene
|
|
un bloque &catch;, la excepción "subirá" la pila de llamadas de la función llamadora
|
|
hasta encontrar un bloque &catch; correspondiente. Todos los bloques &finally; encontrados
|
|
serán ejecutados. Si la pila de llamadas se desenrolla hasta el ámbito global sin
|
|
encontrar un bloque &catch; correspondiente, el programa será terminado con
|
|
un error fatal a menos que se haya definido un manejador global de excepciones.
|
|
</para>
|
|
<para>
|
|
El objeto lanzado debe ser una &instanceof; <interfacename>Throwable</interfacename>.
|
|
Intentar lanzar un objeto que no lo es resultará en un error fatal emitido por PHP.
|
|
</para>
|
|
<para>
|
|
A partir de PHP 8.0.0, la palabra clave &throw; es una expresión y puede ser
|
|
utilizada en cualquier contexto de expresiones. En versiones anteriores era una declaración que debía estar en su propia línea.
|
|
</para>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.catch">
|
|
<title><literal>catch</literal></title>
|
|
<para>
|
|
Un bloque &catch; define cómo reaccionar ante una excepción que ha sido lanzada.
|
|
Un bloque &catch; define uno o más tipos de excepciones o errores que puede
|
|
manejar, y opcionalmente una variable en la que asignar la excepción.
|
|
(Esta variable era requerida en versiones anteriores a PHP 8.0.0)
|
|
El primer bloque &catch; que una excepción o error lanzado encuentre y que corresponda al
|
|
tipo del objeto lanzado manejará el objeto.
|
|
</para>
|
|
<para>
|
|
Varios bloques &catch; pueden ser utilizados para atrapar diferentes
|
|
clases de excepciones. La ejecución normal (cuando ninguna excepción es lanzada
|
|
en el bloque &try;) continúa después del último
|
|
bloque &catch; definido en la secuencia. Las excepciones
|
|
pueden ser lanzadas (&throw;) o relanzadas en un bloque &catch;. De lo contrario,
|
|
la ejecución continuará después del bloque &catch; que haya sido activado.
|
|
</para>
|
|
<para>
|
|
Cuando una excepción es lanzada, el código siguiente al tratamiento no será
|
|
ejecutado y PHP intentará encontrar el primer bloque &catch; correspondiente.
|
|
Si una excepción no es capturada, un error fatal de PHP será
|
|
enviado con un mensaje "<literal>Uncaught Exception ...</literal>"
|
|
indicando que la excepción no pudo ser capturada a menos que un manejador
|
|
de excepciones sea definido con la función
|
|
<function>set_exception_handler</function>.
|
|
</para>
|
|
<para>
|
|
A partir de PHP 7.1, un bloque &catch; puede especificar múltiples excepciones a
|
|
través del carácter pipe (<literal>|</literal>). Esto es útil cuando
|
|
diferentes excepciones de diferentes jerarquías de clases son tratadas
|
|
de la misma manera.
|
|
</para>
|
|
<para>
|
|
A partir de PHP 8.0.0, el nombre de variable para la excepción capturada es
|
|
opcional. Si no se especifica, el bloque &catch; será siempre ejecutado pero
|
|
no tendrá acceso al objeto lanzado.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.finally">
|
|
<title><literal>finally</literal></title>
|
|
<para>
|
|
Un bloque &finally; también puede ser
|
|
especificado después de bloques &catch;. El código dentro
|
|
del bloque &finally; será siempre ejecutado después de los bloques
|
|
&try; y &catch;, independientemente de si
|
|
una excepción ha sido lanzada, antes de continuar con la ejecución normal.
|
|
</para>
|
|
<para>
|
|
Una interacción notable es entre un bloque &finally; y una declaración
|
|
&return;.
|
|
Si una declaración &return; es encontrada dentro de los bloques &try;
|
|
o &catch;, el bloque &finally; será igualmente ejecutado. Además,
|
|
la declaración &return; es evaluada cuando es encontrada, pero el
|
|
resultado será retornado después de que el bloque &finally; sea ejecutado.
|
|
Adicionalmente, si el bloque &finally; contiene también una declaración
|
|
&return; el valor del bloque &finally; es retornado.
|
|
</para>
|
|
<para>
|
|
Otra interacción notable es entre una excepción lanzada en un bloque &try;,
|
|
y una excepción lanzada en un bloque &finally;. Si una excepción es lanzada en ambos bloques,
|
|
entonces, la excepción lanzada en el bloque &finally; será la que se propagará,
|
|
y la excepción lanzada en el bloque &try; será utilizada como excepción previa.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.exception-handler">
|
|
<title>Manejador global de excepciones</title>
|
|
<para>
|
|
Si una excepción es permitida para subir hasta el ámbito global, puede
|
|
ser capturada por un manejador de excepciones global si ha sido definido. La función
|
|
<function>set_exception_handler</function> puede definir una función que será
|
|
llamada en lugar de un bloque &catch; si ningún otro bloque es invocado.
|
|
El efecto es esencialmente idéntico a envolver el programa entero en un
|
|
bloque &try;-&catch; con esta función como &catch;.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.notes">
|
|
&reftitle.notes;
|
|
|
|
<note>
|
|
<para>
|
|
Las funciones internas de PHP utilizan principalmente el
|
|
<link linkend="ini.error-reporting">Error reporting</link>, solo las extensiones
|
|
<link linkend="language.oop5">orientadas a objetos</link>
|
|
utilizan excepciones. Sin embargo, los errores pueden ser fácilmente convertidos en
|
|
excepciones con <link linkend="class.errorexception">ErrorException</link>.
|
|
Sin embargo, esta técnica solo funciona para errores no fatales.
|
|
</para>
|
|
<example>
|
|
<title>Convertir el error reporting en excepciones</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>
|
|
La <link linkend="intro.spl">biblioteca estándar PHP (SPL)</link> proporciona
|
|
un buen número <link linkend="spl.exceptions">de excepciones adicionales</link>.
|
|
</para>
|
|
</tip>
|
|
</sect1>
|
|
|
|
<sect1 annotations="chunk:false" xml:id="language.exceptions.examples">
|
|
&reftitle.examples;
|
|
|
|
<example>
|
|
<title>Lanzar una excepción</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
function inverse($x) {
|
|
if (!$x) {
|
|
throw new Exception('División por cero.');
|
|
}
|
|
return 1/$x;
|
|
}
|
|
|
|
try {
|
|
echo inverse(5) . "\n";
|
|
echo inverse(0) . "\n";
|
|
} catch (Exception $e) {
|
|
echo 'Excepción recibida: ', $e->getMessage(), "\n";
|
|
}
|
|
|
|
// Continuar la ejecución
|
|
echo "¡Hola mundo!\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
0.2
|
|
Excepción recibida: División por cero.
|
|
¡Hola mundo!
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>Manejo de la excepción con un bloque &finally;</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
function inverse($x) {
|
|
if (!$x) {
|
|
throw new Exception('División por cero.');
|
|
}
|
|
return 1/$x;
|
|
}
|
|
|
|
try {
|
|
echo inverse(5) . "\n";
|
|
} catch (Exception $e) {
|
|
echo 'Excepción recibida: ', $e->getMessage(), "\n";
|
|
} finally {
|
|
echo "Primer fin.\n";
|
|
}
|
|
|
|
try {
|
|
echo inverse(0) . "\n";
|
|
} catch (Exception $e) {
|
|
echo 'Excepción recibida: ', $e->getMessage(), "\n";
|
|
} finally {
|
|
echo "Segundo fin.\n";
|
|
}
|
|
|
|
// Continuar la ejecución
|
|
echo "¡Hola mundo!\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
0.2
|
|
Primer fin.
|
|
Excepción recibida: División por cero.
|
|
Segundo fin.
|
|
¡Hola mundo!
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>Interacción entre el bloque &finally; y &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>Herencia de una excepción</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class MyException extends Exception { }
|
|
|
|
class Test {
|
|
public function testing() {
|
|
try {
|
|
try {
|
|
throw new MyException('foo!');
|
|
} catch (MyException $e) {
|
|
// se relanza
|
|
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>Manejo de excepciones de captura múltiple</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>Omitir la variable capturada</title>
|
|
<para>Solo permitido en PHP 8.0.0 y versiones posteriores.</para>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
function test() {
|
|
throw new SpecificException('Oopsie');
|
|
}
|
|
|
|
try {
|
|
test();
|
|
} catch (SpecificException) {
|
|
print "Se lanzó una SpecificException, pero no nos importa con los detalles.";
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Se lanzó una SpecificException, pero no nos importa con los detalles.
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>Throw como expresión</title>
|
|
<para>Solo permitido en PHP 8.0.0 y versiones posteriores.</para>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class SpecificException extends Exception {}
|
|
|
|
function test() {
|
|
do_something_risky() or throw new Exception('No funcionó');
|
|
}
|
|
|
|
function do_something_risky() {
|
|
return false; // Simular un fallo
|
|
}
|
|
|
|
try {
|
|
test();
|
|
} catch (Exception $e) {
|
|
print $e->getMessage();
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
No funcionó
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>Excepción en try y en finally</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
try {
|
|
try {
|
|
throw new Exception(message: 'Third', previous: new Exception('Fourth'));
|
|
} finally {
|
|
throw new Exception(message: 'First', previous: new Exception('Second'));
|
|
}
|
|
} 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) "First"
|
|
string(6) "Second"
|
|
string(5) "Third"
|
|
string(6) "Fourth"
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="language.exceptions.extending">
|
|
<title>Extender las Excepciones</title>
|
|
<para>
|
|
Una clase de excepción definida por el usuario puede ser definida extendiendo
|
|
la clase Exception integrada. Los miembros y las propiedades a continuación muestran
|
|
lo que está accesible en la clase hija que deriva de la clase Exception
|
|
integrada.
|
|
</para>
|
|
<example>
|
|
<title>La clase de excepción integrada</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Exception implements Throwable
|
|
{
|
|
protected $message = 'Unknown exception'; // Mensaje de excepción
|
|
private $string; // caché de __toString
|
|
protected $code = 0; // código de excepción definido por el usuario
|
|
protected $file; // nombre de archivo fuente de la excepción
|
|
protected $line; // línea fuente de la excepción
|
|
private $trace; // rastro de la pila de ejecución
|
|
private $previous; // excepción previa si excepción anidada
|
|
|
|
public function __construct($message = '', $code = 0, ?Throwable $previous = null);
|
|
|
|
final private function __clone(); // Inhibe la duplicación de excepciones.
|
|
|
|
final public function getMessage(); // mensaje de la excepción
|
|
final public function getCode(); // código de la excepción
|
|
final public function getFile(); // nombre del archivo fuente
|
|
final public function getLine(); // línea fuente
|
|
final public function getTrace(); // array de la pila de ejecución
|
|
final public function getPrevious(); // la excepción previa
|
|
final public function getTraceAsString(); // rastro en forma de string
|
|
|
|
// Puede ser redefinido
|
|
public function __toString(); // string formateado para la visualización
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
Si una clase extiende la clase Exception integrada y redefine el <link
|
|
linkend="language.oop5.decon">constructor</link>, se recomienda fuertemente
|
|
que también llame a <link
|
|
linkend="language.oop5.paamayim-nekudotayim">parent::__construct()</link>
|
|
para asegurarse de que todos los datos disponibles han sido correctamente asignados.
|
|
El método <link linkend="language.oop5.magic">__toString()</link> puede ser
|
|
redefinido para proporcionar una salida personalizada cuando el objeto es presentado
|
|
en forma de string.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Las excepciones no pueden ser clonadas. Intentar <link
|
|
linkend="language.oop5.cloning">clonar</link> una Exception resultará en un
|
|
error fatal <constant>E_ERROR</constant>.
|
|
</para>
|
|
</note>
|
|
<example>
|
|
<title>Extender la clase Exception</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/**
|
|
* Define una clase de excepción personalizada.
|
|
*/
|
|
class MyException extends Exception
|
|
{
|
|
// Redefinir la excepción para que el mensaje no sea opcional.
|
|
public function __construct($message, $code = 0, ?Throwable $previous = null) {
|
|
// código
|
|
|
|
// asegurarse de que todo está correctamente asignado
|
|
parent::__construct($message, $code, $previous);
|
|
}
|
|
|
|
// Representación personalizada del objeto en forma de string.
|
|
public function __toString() {
|
|
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
|
|
}
|
|
|
|
public function customFunction() {
|
|
echo "Una función personalizada para este tipo de excepción\n";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crear una clase para probar la excepción
|
|
*/
|
|
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:
|
|
// Lanzar una excepción personalizada
|
|
throw new MyException('1 no es un parámetro válido', 5);
|
|
break;
|
|
|
|
case self::THROW_DEFAULT:
|
|
// Lanzar la por defecto.
|
|
throw new Exception('2 no está permitido como parámetro', 6);
|
|
break;
|
|
|
|
default:
|
|
// Ninguna excepción, el objeto será creado.
|
|
$this->var = $avalue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ejemplo 1
|
|
try {
|
|
$o = new TestException(TestException::THROW_CUSTOM);
|
|
} catch (MyException $e) { // Será capturada
|
|
echo "MyException capturada\n", $e;
|
|
$e->customFunction();
|
|
} catch (Exception $e) { // Ignorado
|
|
echo "Exception por defecto capturada\n", $e;
|
|
}
|
|
|
|
// Continuar la ejecución
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
// Ejemplo 2
|
|
try {
|
|
$o = new TestException(TestException::THROW_DEFAULT);
|
|
} catch (MyException $e) { // No coincide con este tipo
|
|
echo "MyException capturada\n", $e;
|
|
$e->customFunction();
|
|
} catch (Exception $e) { // Será capturada
|
|
echo "Exception por defecto capturada\n", $e;
|
|
}
|
|
|
|
// Continuar la ejecución
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
// Ejemplo 3
|
|
try {
|
|
$o = new TestException(TestException::THROW_CUSTOM);
|
|
} catch (Exception $e) { // Será capturada
|
|
echo "Exception por defecto capturada\n", $e;
|
|
}
|
|
|
|
// Continuar la ejecución
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
// Ejemplo 4
|
|
try {
|
|
$o = new TestException();
|
|
} catch (Exception $e) { // Saltado, ninguna excepción
|
|
echo "Exception por defecto capturada\n", $e;
|
|
}
|
|
|
|
// Continuar la ejecución
|
|
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
|
|
-->
|