try set_error_handler new generate exceptions error custom catch all php exception

new - En PHP5, ¿debo usar Excepciones o trigger_error/set_error_handler?



try catch php 7 (9)

¿Cuáles son los pros / contra de hacer de cualquier manera? ¿Hay un camino correcto (tm)?


Introducción

En mi experiencia personal, como regla general, prefiero usar excepciones en mi código en lugar de trigger_error. Esto se debe principalmente a que el uso de Excepciones es más flexible que la activación de errores. Y, en mi humilde opinión, esto también es beneficioso no solo para mí como para el desarrollador de terceros.

  1. Puedo extender la clase Exception (o usar códigos de excepción) para diferenciar explícitamente los estados de mi biblioteca. Esto me ayuda a mí y a desarrolladores de terceros a manejar y depurar el código. Esto también expone dónde y por qué puede fallar sin necesidad de buscar código fuente.
  2. De hecho, puedo detener la ejecución de mi Biblioteca sin detener la ejecución del script.
  3. El desarrollador de terceros puede encadenar mis excepciones (en PHP> 5.3. *). Muy útil para la depuración y puede ser útil para manejar situaciones en las que mi biblioteca puede fallar debido a razones dispares.

Y puedo hacer todo esto sin imponer cómo debe manejar las fallas de mi biblioteca. (es decir, crear funciones complejas de manejo de errores). Puede usar un bloque try catch o simplemente usar un manejador genérico de excepciones

Nota:

Algunos de estos puntos, en esencia, también son válidos para trigger_error, un poco más complejo de implementar. Los bloques de prueba son realmente fáciles de usar y muy amigables con el código.

Ejemplo

Creo que este es un ejemplo que podría ilustrar mi punto de vista:

class HTMLParser { protected $doc; protected $source = null; public $parsedHtml; protected $parseErrors = array(); public function __construct($doc) { if (!$doc instanceof DOMDocument) { // My Object is unusable without a valid DOMDOcument object // so I throw a CriticalException throw new CriticalException("Could not create Object Foo. You must pass a valid DOMDOcument object as parameter in the constructor"); } $this->doc = $doc; } public function setSource($source) { if (!is_string($source)) { // I expect $source to be a string but was passed something else so I throw an exception throw new InvalidArgumentException("I expected a string but got " . gettype($source) . " instead"); } $this->source = trim($source); return $this; } public function parse() { if (is_null($this->source) || $this->source == '''') { throw new EmptyStringException("Source is empty"); } libxml_use_internal_errors(true); $this->doc->loadHTML($this->source); $this->parsedHtml = $this->doc->saveHTML(); $errors = libxml_get_errors(); if (count($errors) > 0) { $this->parseErrors = $errors; throw new HtmlParsingException($errors[0]->message,$errors[0]->code,null, $errors[0]->level,$errors[0]->column,$errors[0]->file,$errors[0]->line); } return $this; } public function getParseErrors() { return $this->parseErrors; } public function getDOMObj() { return clone $this->doc; } }

Explicación

En el constructor lanzo una CriticalException si el param pasado no es del tipo DOMDocument porque sin él mi biblioteca no funcionará en absoluto.

(Nota: simplemente podría escribir __construct(DOMDocument $doc) pero esto es solo un ejemplo).

En el método setsource() arrojo una InvalidArgumentException si el param pasado es algo distinto de una cadena. Prefiero detener la ejecución de la biblioteca aquí porque la propiedad de origen es una propiedad esencial de mi clase y un valor no válido propagará el error en toda mi biblioteca.

El método parse() suele ser el último método invocado en el ciclo. Aunque lanzo XmlParsingException si libXML encuentra un documento con formato incorrecto, el análisis se completa primero y los resultados se pueden usar (hasta cierto punto).

Manejo de la biblioteca de ejemplos

Aquí hay un ejemplo de cómo manejar esta biblioteca inventada:

$source = file_get_contents(''http://www.somehost.com/some_page.html''); try { $parser = new HTMLParser(new DOMDocument()); $parser->setSource($source) ->parse(); } catch (CriticalException $e) { // Library failed miserably, no recover is possible for it. // In this case, it''s prorably my fault because I didn''t pass // a DOMDocument object. print ''Sorry. I made a mistake. Please send me feedback!''; } catch (InvalidArgumentException $e) { // the source passed is not a string, again probably my fault. // But I have a working parser object. // Maybe I can try again by typecasting the argument to string var_dump($parser); } catch (EmptyStringException $e) { // The source string was empty. Maybe there was an error // retrieving the HTML? Maybe the remote server is down? // Maybe the website does not exist anymore? In this case, // it isn''t my fault it failed. Maybe I can use a cached // version? var_dump($parser); } catch (HtmlParsingException $e) { // The html suplied is malformed. I got it from the interwebs // so it''s not my fault. I can use $e or getParseErrors() // to see if the html (and DOM Object) is usable // I also have a full functioning HTMLParser Object and can // retrieve a "loaded" functioning DOMDocument Object var_dump($parser->getParseErrors()); var_dump($parser->getDOMObj()); } $var = ''this will print wether an exception was previously thrown or not''; print $var;

Puede llevar esto más allá y anidar, intente capturar bloques, cadenas de excepciones, ejecutar código selectivo siguiendo una ruta de cadena de excepción determinada, registro selectivo, etc.

Como nota al margen, el uso de Excepciones no significa que la ejecución del PROGRAMA se detendrá, solo significa que el código que depende de mi objeto será anulado. Depende de mí o del desarrollador de terceros hacer con él lo que quiera.


Debe usar excepciones en "Circunstancias excepcionales", es decir, cuando llama a un método doFoo () que debe esperar que funcione, si por alguna razón doFoo no puede hacer su trabajo, entonces debe generar una excepción.

Una gran cantidad de viejos códigos php tomaría el enfoque de devolver falsa o nula cuando ocurra una falla, pero esto dificulta la depuración, las excepciones hacen que esta depuración sea mucho más fácil.

Por ejemplo, supongamos que tiene un método llamado getDogFood () que devuelve una matriz de objetos DogFood, si llamó a este método y devuelve un valor nulo cuando algo falla, ¿cómo podrá su código de llamada saber si se devolvió el valor nulo porque hubo un error? o simplemente no hay comida para perros disponible?

En cuanto a las bibliotecas de códigos heredados que utilizan el registro de errores incorporado de php, puede anular el registro de errores con la función set_error_handler (), que podría utilizar para volver a lanzar una excepción genérica.

Ahora que tiene todo su código arrojando excepciones detalladas, puede decidir libremente qué hacer con ellos, en algunas partes de su código puede que desee atraparlos y probar métodos alternativos o puede iniciar sesión utilizando sus propias funciones de registro que podría iniciar sesión en una base de datos, archivo, correo electrónico, lo que prefiera. En resumen: las excepciones son más flexibles.


Depende de la situación. Tiendo a usar Excepciones cuando escribo lógica de negocios / aplicaciones internas, y trigger_error para Validator y cosas por el estilo.

El profesional de usar Excepciones en el nivel lógico es permitir que su aplicación lo haga en caso de tal error. Permites que la aplicación elija en lugar de que la lógica comercial sepa cómo presentar el error.

Los profesionales de usar trigger_error para Validator y cosas de esa naturaleza son, por ejemplo,

try { $user->login(); } catch (AuthenticationFailureException $e) { set_error_handler("my_login_form_handler"); trigger_error("User could not be logged in. Please check username and password and try again!"); } catch (PersistenceException $pe) { // database unavailable set_error_handler("my_login_form_handler"); trigger_error("Internal system error. Please contact the administrator."); }

donde my_login_form_handler pretiende la cadena y coloca el elemento en un área visible encima del formulario de inicio de sesión.


La idea de excepción es elegante y hace que el proceso de manejo de errores sea tan fluido. pero esto solo se aplica cuando tienes clases de excepción apropiadas y en desarrollo de equipo, una cosa más importante son las excepciones "estándar". por lo tanto, si planea usar excepciones, es mejor que primero estandarice sus tipos de excepción, o la mejor opción es usar excepciones de algún marco popular. Otra cosa que se aplica a PHP (donde se puede escribir el orientador de objetos de código combinado con el código estructural), es que si está escribiendo toda su aplicación usando clases. Si está escribiendo orientado a objetos, entonces las excepciones son más seguras. después de todo, creo que el proceso de manejo de errores será mucho más suave con la excepción que trigger_error y esas cosas.


Las Excepciones son la forma moderna y robusta de señalar una condición de error / una situación excepcional. Usalos, usalos a ellos :)


Me encanta la idea de usar excepciones, pero a menudo tengo bibliotecas de terceros involucradas, y luego, si no usan excepciones, terminas con 3-4 enfoques diferentes del problema. Zend usa excepciones. CakePHP utiliza un controlador de error personalizado, y la mayoría de las bibliotecas PEAR utilizan el objeto PEAR :: Error.

Yo que HABÍA una sola manera verdadera en este sentido. La ruta personalizada de controladores de errores es probablemente la más flexible en esta situación. Sin embargo, las excepciones son una gran idea si solo está utilizando su propio código o está utilizando bibliotecas que lo usan.

Desafortunadamente en el mundo de PHP todavía estamos sufriendo la negativa a morir de PHP4, por lo que las excepciones, aunque pueden representar las mejores prácticas, han sido increíblemente lentas para ponerse al día mientras todos escriben cosas para poder trabajar tanto en 4 y 5. Esperemos que esta debacle termine ahora, aunque en el momento en que lo haga, tendremos tensiones entre 6 y 5 en su lugar ...

/ yo tengo la cabeza en las manos ...


Obviamente, no hay "un camino correcto", pero hay una multitud de opiniones sobre este. ;)

Personalmente utilizo trigger_error para cosas que las excepciones no pueden hacer, es decir, avisos y advertencias (es decir, cosas que desea registrar pero no detiene el flujo de la aplicación de la misma manera que los errores / excepciones (incluso si los detecta en algún nivel) )).

También utilizo principalmente excepciones para condiciones que se supone son irrecuperables (para el que llama del método en el que se produce la excepción), es decir, errores graves. No utilizo excepciones como alternativa a devolver un valor con el mismo significado, si eso es posible de una manera no intrincada. Por ejemplo, si creo un método de búsqueda, normalmente devuelvo un valor nulo si no encuentra lo que estaba buscando en lugar de arrojar una EntityNotFoundException (o equivalente).

Entonces mi regla de oro es esta:

  • Siempre que no encontrar algo sea un resultado razonable, me resulta mucho más fácil regresar y verificar valores nulos (o algún otro valor predeterminado) que manejarlo usando una cláusula try-catch.
  • Si, por otro lado, no encontrarlo es un error grave que no está dentro del alcance de la persona que llama para recuperarse, todavía lanzaría una excepción.

La razón para lanzar excepciones en el último caso (en lugar de desencadenar errores) es que las excepciones son mucho más expresivas, dado que se usan subclases de Excepción correctamente nombradas. Encuentro que usar las excepciones de la Biblioteca Estándar de PHP es un buen punto de partida para decidir qué excepciones usar: http://www.php.net/~helly/php/ext/spl/classException.html

Sin embargo, es posible que desee extenderlos para obtener excepciones más semánticamente correctas para su caso particular.


Usar excepciones no es una buena idea en la era de la integración de aplicaciones de terceros .

Porque, en el momento en que intentas integrar tu aplicación con otra cosa, o la aplicación de otra persona con la tuya, toda tu aplicación se detendrá en el momento en que una clase en un plugin de terceros arroje una excepción. Incluso si tiene un manejo completo de errores, el registro implementado en su propia aplicación, el objeto aleatorio de alguien en un complemento de terceros arrojará una excepción y toda su aplicación se detendrá allí mismo.

INCLUSO si tiene los medios en su aplicación para compensar el error de esa biblioteca que está utilizando ....

Un caso en el ejemplo puede ser una biblioteca de inicio de sesión social de un tercero que arroja una excepción porque el proveedor de inicio de sesión social devolvió un error y mata innecesariamente toda su aplicación: hybridauth, por cierto. Entonces, allí tienes una aplicación completa, y allí tienes una biblioteca que te brinda funcionalidades adicionales, en este caso, inicio de sesión social, y aunque tienes muchas cosas secundarias en el caso de que un proveedor no se autentique (tu sistema de inicio de sesión, más como 20 o más proveedores de inicio de sesión social), su aplicación ENTERA se detendrá. Y terminará teniendo que cambiar la biblioteca de terceros para evitar estos problemas, y se perderá el punto de utilizar una biblioteca de terceros para acelerar el desarrollo.

Este es un error de diseño serio con respecto a la filosofía de manejo de errores en PHP. Seamos realistas: debajo del otro extremo de la mayoría de las aplicaciones desarrolladas hoy, hay un usuario. Ya sea un usuario de intranet, ya sea un usuario a través de Internet, ya sea un administrador del sistema, no importa; generalmente hay un usuario.

Y, tener una aplicación muere en su cara sin que haya nada que pueda hacer en ese punto que no sea volver a una página anterior y tener una toma en la oscuridad con respecto a lo que está tratando de hacer, como usuario, es malo, mala práctica desde el lado del desarrollo. Sin mencionar, un error interno que solo los desarrolladores deberían saber debido a muchas razones (desde la usabilidad hasta la seguridad) que se lanzan en la cara de un usuario.

Como resultado, voy a tener que soltar una biblioteca particular de terceros (hybridauth en este caso) y no usarla en mi aplicación, únicamente por ese motivo. A pesar de que hybridauth es una muy buena biblioteca, y aparentemente se han dedicado muchos buenos esfuerzos en ella, con un phletora de capacidades.

Por lo tanto, debe abstenerse de usar excepciones en su código. INCLUSO si el código que está haciendo ahora, es el código de nivel superior que ejecutará su aplicación, y no una biblioteca, es posible que desee incluir todo o parte de su código en otros proyectos, o tenga que integrar partes o en su totalidad con otro código tuyo o código de terceros. Y si usó excepciones, terminará con la misma situación: la totalidad de las aplicaciones / integraciones mueren en su cara, incluso si cuenta con los medios adecuados para manejar cualquier problema que brinde un fragmento de código.


Si desea utilizar excepciones en lugar de errores para toda la aplicación, puede hacerlo con ErrorException y un controlador de errores personalizado (consulte la página ErrorException para obtener un controlador de errores de muestra). El único inconveniente de este método es que los errores no fatales arrojarán excepciones, que siempre son fatales a menos que sean detectadas. Básicamente, incluso un E_NOTICE detendrá toda su aplicación si su configuración de error_reporting no los suprime.

En mi opinión, hay varios beneficios al usar ErrorException:

  1. Un controlador de excepciones personalizado le permitirá mostrar mensajes agradables, incluso para errores, utilizando set_exception_handler .
  2. No interrumpe el código existente de ninguna manera ... trigger_error y otras funciones de error seguirán funcionando normalmente.
  3. Hace realmente difícil ignorar los errores de codificación estúpidos que activan E_NOTICE sy E_WARNING .
  4. Puede usar try / catch para ajustar el código que puede generar un error PHP (no solo excepciones), que es una buena manera de evitar el uso del truco de supresión de errores @ :

    try { $foo = $_GET[''foo'']; } catch (ErrorException $e) { $foo = NULL; }

  5. Puede envolver su secuencia de comandos completa en un único bloque try / catch si desea mostrar un mensaje amigable a sus usuarios cuando ocurre un error no detectado. (Haga esto con cuidado, porque solo se registran errores y excepciones no detectadas).