📜 ⬆️ ⬇️

PHP error and exception handling

This “small” article is a development of the topic covered in this article.
As you know, PHP was born a long time ago and already then the question arose of what to do with the errors that occurred. Perl, which is the undoubted progenitor of PHP by default, did not have any error handling system. When any error occurred, the server threw out the 500th error and that was it. Therefore, Warnings, Fatal Errors and Notices were a real breakthrough in alleviating the already hard work of a programmer. However, as time went on, the PHP mechanisms did not change, and technologies, as is known, do not like to stand still.

And here in PHP 5.0, finally, in the arsenal of programmers appeared such a powerful tool as an exception or Exception. There are many advantages of Exception, I will describe only a few (perhaps, I express myself inaccurately or even illiterately, but I was just too lazy to look for scientific terms to describe the advantages, because they are described in their own words):

The handling of standard PHP errors is extremely limited:
It is clear that the standard error handling mechanism is outdated and is present in the language only for compatibility reasons.
In this small article I will try to highlight how error handling can be made universal by transferring it to the use of the exception mechanism.
The main idea: we put our handler for standard errors and throw an exception in it:
  1. <? php
  2. class MyException extends Exception {
  3. public function __construct ($ message, $ errorLevel = 0, $ errorFile = '' , $ errorLine = 0) {
  4. parent :: __ construct ($ message, $ errorLevel);
  5. $ this -> file = $ errorFile;
  6. $ this -> line = $ errorLine;
  7. }
  8. }
  9. set_error_handler ( create_function ( '$ c, $ m, $ f, $ l' , 'throw new MyException ($ m, $ c, $ f, $ l);' ), E_ALL);
  10. ?>
* This source code was highlighted with Source Code Highlighter .

This code must be placed in a separate file and connect it only once. The MyException class extends the standard Exception class by adding two additional parameters to the constructor: the file and the line number with an error.
The set_error_handler function sets as an error handler a dynamically created lambda function (callback), which generates an exception in case of an error. I especially ask you to pay attention to the second parameter of the set_error_handler function. This parameter is very important, since it determines for which types of errors a custom (that is, our) handler will be called, and for which standard ones. In this example, I set the value to E_ALL, which means that the handler will be called for all types of errors.
If we do not want to handle some types of errors, for example, Notice, then we can easily indicate this:
set_error_handler ( create_function ( '$ c, $ m, $ f, $ l' , 'throw new MyException ($ m, $ c, $ f, $ l);' ), E_ALL & ~ E_NOTICE); * This source code was highlighted with Source Code Highlighter .

However, the ideal approach, as it seems to me, is the handling of all errors, but for some types, in particular, notice, it would be advisable not to throw an exception, but simply to display information on the screen:
set_error_handler ( create_function ( '$ c, $ m, $ f, $ l' , 'if ($ c === E_NOTICE) {echo' This is notice: '. $ m} else {throw new MyException ($ m, $ c, $ f, $ l);} ' ), E_ALL); * This source code was highlighted with Source Code Highlighter .

Now consider an example close to life. Task:
There is a registration form on the site, it is necessary to implement with the help of exceptions, the processing of validation errors and the issuance of appropriate warnings to the user.
There are actually two difficulties here:
  1. Display all errors at once, not one by one.
  2. Separate validation error handling from other exception handling

Decision:
The main difficulty here for us will be the very notorious advantage of Exception, which is that when throwing an exception, there is a exit from the control structures to the first catch block (or to the end of the script). In order to circumvent this pitfall, we define a new descendant class FormFieldsListException, in which we implement an error accumulation mechanism, and we will only throw an exception after validating all the fields. In the FormFieldsListException class, we define the protected member $ _list in which we will store the data. To simplify working with the $ _list array, we indicate that the class will implement two interfaces: ArrayAccess to access the elements of the array and Iterator to work in a loop. When initializing the validation verification method, we create a FormFieldsListException object, and then, as errors are detected, add them to the FormFieldsListException object, as in a regular array.
  1. <? php
  2. class FormFieldsListException extends Exception implements ArrayAccess, Iterator {
  3. protected $ _list = array ();
  4. public function __construct () {
  5. }
  6. public function offsetExists ($ index) {
  7. return isset ($ this -> _ list [$ index]);
  8. }
  9. public function offsetGet ($ index) {
  10. return $ this -> _ list [$ index];
  11. }
  12. public function offsetSet ($ index, $ value) {
  13. if (isset ($ index)) {
  14. $ this -> _ list [$ index] = $ value;
  15. }
  16. else {
  17. $ this -> _ list [] = $ value;
  18. }
  19. }
  20. public function offsetUnset ($ index) {
  21. unset ($ this -> _ list [$ index]);
  22. }
  23. public function current () {
  24. return current ($ this -> _ list);
  25. }
  26. public function key () {
  27. return key ($ this -> _ list);
  28. }
  29. public function next () {
  30. return next ($ this -> _ list);
  31. }
  32. public function rewind () {
  33. return reset ($ this -> _ list);
  34. }
  35. public function valid () {
  36. return ( bool ) $ this -> current ();
  37. }
  38. }
  39. ?>
* This source code was highlighted with Source Code Highlighter .

After the end of the validation procedure, we check if any error messages were entered. If so, we “throw” the prepared exception object.
To catch an exception, we use two catch blocks: for FormFieldsListException and for all other exceptions. This allows you to specify different types of actions when different types of exceptions occur.
  1. <? php
  2. function validateForm () {
  3. $ e = new FormFieldsListException ();
  4. if ($ errorInFirstField) {
  5. $ e [] = 'Error in first field' ;
  6. }
  7. if ($ errorInSecondField) {
  8. $ e [] = 'Error in second field' ;
  9. }
  10. if (( bool ) $ e-> current ()) {
  11. throw $ e;
  12. }
  13. }
  14. try {
  15. validateForm ();
  16. }
  17. catch (FormFieldsListException $ error) {
  18. echo '<b> Errors in the fields </ b>: <br />' ;
  19. foreach ($ error as $ e) {
  20. echo $ e. '<br />' ;
  21. }
  22. }
  23. catch (Exception $ error) {
  24. echo 'Not validation error! ' . $ error-> getMessage ();
  25. }
  26. ?>
* This source code was highlighted with Source Code Highlighter .

So here! :)
A properly designed exception system can seriously simplify the programmer’s life, especially when developing applications using the MVC pattern. As a little research has shown, the PHP5 exception handling system carries considerable reserves for upgrading and use in specific situations.
PS : Some of the programmers I showed this article consider the use of exceptions to validate forms, to put it mildly, not the best option (by the way, I would ask readers who are “in the subject” to comment on this), so please consider this example just a learning example, not a guide to action.
PPS : Many thanks to comrade ashofthedream , the dispute with which prompted me to study exceptions in more detail.

UPD : Moved to PHP Blog

')

Source: https://habr.com/ru/post/30399/


All Articles