PHP 1.28 - Error Handling & Error Handlers
There are different types of errors that can be generated by PHP. We have fatal errors, syntax errors, notices, parse errors, and so on. Some of these errors will stop the script execution, like fatal errors, for example, but some will not, like warnings.
PHP determines what errors to report based on the error reporting configuration in php.ini, which we discussed in the last lesson, and you could override that by calling error_reporting explicitly within your code at runtime, which allows you to change the reporting level. If you set error_reporting to zero, it will turn off the reporting so no errors will be reported, and if you set it to E_ALL, it will report all errors including warnings.
You should always use the constants to set the reporting levels or use the bit mask, which basically combines multiple reporting levels with bitwise operators to form the desired reporting level. For example, if you want to report everything except warnings, you could do:
<?php
error_reporting(E_ALL & ~E_WARNING);
And now this will report everything except warnings. I recommend using both E_ALL for production and development, as I mentioned in the last lesson, especially for development because that way you're able to catch bugs early on.
Also, as mentioned before, you're able to specify the levels of reporting using the predefined constants. Let's open the list of available error-related constants in phpdocs and review them quickly (Link after the lesson):
For example, E_ERROR is the fatal error and it will stop the script execution. We also see the E_WARNING, E_NOTICE, E_PARSE, and so on. Let's scroll down a bit and we see constants like E_USER_ERROR, E_USER_WARNING, and so on. And these are like the other E_ERROR and E constants. The difference is that the ones with the "USER" are generated manually by using the trigger_error function, which we'll cover in a minute. We also have the E_DEPRECATED, E_USER_DEPRECATED, and so on.
So I mentioned that you're able to manually trigger an error. You can do that by calling the trigger_error()
function and passing the error message and the error level as arguments. We could also do E_USER_ERROR just to show you that this will stop the script execution because we're triggering a fatal error:
<?php
trigger_error('Example error', E_USER_ERROR);
echo 1;
Fatal error: Example error in
If we refresh the page, we see that it triggered the fatal error and stopped the script execution because we don't see anything being printed. However, if we change it to E_USER_WARNING and refresh, now we see "Triggered warning" but it did not stop the execution and one is printed on the screen:
<?php
trigger_error('Example error', E_USER_WARNING);
echo 1;
Warning: Example error
1
Quick note here that you can only use the E_USER constants when triggering errors manually. You cannot trigger regular E_WARNING, for example. If you do this, you will get a fatal error letting you know that you must use one of the E_USER error constants when triggering errors manually.
Alright, let's continue. So whenever something happens in PHP, PHP will determine if the error has to be displayed or not by using the display_errors configuration directive, and we talked about that in the last lesson. You should always have this turned off in production to avoid exposing sensitive information and internal errors to the user. These errors will be logged for you to review even when you are not displaying them, as long as you have the error logging turned on, which we also talked about in the last lesson. The location of the error log depends on a few factors, but XAMPP makes it very easy to access. So you could easily open it by clicking "logs" and then "PHP error log". We'll also talk about how to find error logs on the server itself once we get to that part of the course, which is going to be in
Of in production to avoid exposing some sensitive information and internal errors to the user. These errors will be logged for you to review, even when you are not displaying them, as long as you have the error logging turned on, which we also talked about in the last lesson.
The location of the error log depends on a few factors, but XAMPP makes it very easy to access. So, you could easily open it by clicking "logs" and then "PHP error log". We'll also talk about how to find error logs on the server itself once we get to that part of the course, which is going to be in the third section of the course.
We could also manually log errors by using the error_log function. You could pass the messages as the argument, and that will be logged in that file.
So, how do we handle errors? We haven't talked about how to actually handle these errors. Luckily, PHP allows us to create a custom error handler to tell PHP how to handle errors at runtime. This gives you the power to customize it to your needs. Maybe you want to perform some cleanup actions when the error is called or log it in a certain way, and so on.
So, to register a custom error handler, we first need to create the function. Let's call it "error_handler". And this function has to accept at least two arguments. The first argument has to be the error type, which is an integer, and the second argument is the error message. You could also then optionally accept the file and the line number where the error happened:
<?php
function errorHandler(int $type, string $message, ?string $file = null, ?int $line = null) {
echo $type . ': ' . $message . ' in ' . $file . ' on line ' . $line;
}
Now, within this function, we can do whatever we want. You can put if-else conditionals or switch statements to handle different types of errors differently, and so on. To demonstrate how this works, I will simply print the type, message, file, and line on the screen. But you would not want to do that in production or a real application because it kind of defeats the purpose of using custom error handlers because, as mentioned before, you don't want to expose your errors to the user. But if you're just going to print it in the error handler, then it doesn't really solve any issues. But I'm just going to do that for the sake of demonstration to show you how it works.
You also wouldn't want to display messages unescaped like that, and don't worry about escaping or security for now. We'll talk about that later in the course.
You can return false to fall back to standard PHP's error handling, or return something other than false, like true, to just continue with the script execution. You might want to do that in certain cases, maybe for certain error types. But you might also want to stop the script execution for fatal or important errors, and you can do that by using the exit statement:
<?php
function errorHandler(int $type, string $message, ?string $file = null, ?int $line = null) {
echo $type . ': ' . $message . ' in ' . $file . ' on line ' . $line;
exit;
}
So once we have the function ready, now we can register it as the error handler by using the set_error_handler function. It accepts the custom error handler, called that function as the first argument, and the error level as the second argument. So, we could set it to E_ALL to enable custom error handling for all errors, and you can customize this to whatever error level you need:
<?php
function errorHandler(int $type, string $message, ?string $file = null, ?int $line = null) {
echo $type . ': ' . $message . ' in ' . $file . ' on line ' . $line;
exit;
}
set_error_handler('errorHandler', E_ALL);
Quick note here that this custom error handler will overwrite what you have set for the error reporting configuration setting. So, if you had your error reporting set to report everything except warnings, our custom error handler would overwrite that because we are now handling all kinds of errors, including the warnings.
To demonstrate that:
<?php
function errorHandler(int $type, string $message, ?string $file = null, ?int $line = null) {
echo $type . ': ' . $message . ' in ' . $file . ' on line ' . $line;
exit;
}
error_reporting(E_ALL & ~E_WARNING);
echo $x;
set_error_handler('errorHandler', E_ALL);
Because this variable $x
has not been defined, it would trigger an undefined variable warning. But because of our error reporting we're not reporting that, if we update the error reporting:
<?php
function errorHandler(int $type, string $message, ?string $file = null, ?int $line = null) {
echo $type . ': ' . $message . ' in ' . $file . ' on line ' . $line;
exit;
}
error_reporting(E_ALL);
echo $x;
set_error_handler('errorHandler', E_ALL);
Warning: Undefined variable $x
Now we see the warning.
This is it for this lesson. We have covered the very basics of error handling, and this is just the way to handle errors procedurally. We have not talked about something called exceptions, which are thrown by most errors in PHP, and you could throw your own custom exceptions as well. Exceptions are an object-oriented way of handling errors, and we'll cover exceptions and error handling in more detail in the second section of the course.