Exception handling in PHP
For developers who do not have full-fledged programming experience, exceptions are generally a dark forest ... Let's try to figure it out.
What are "exceptions"?
By "exception" is meant handling of exceptional situations . A simple example from "big" languages.
The file is read into some variable. Before that, a block of memory is allocated for this. In the process of reading a file, an exception occurs , for example, the file has been deleted or it is blocked for reading. This program crashes, which means that the memory area has not been freed.
Therefore, such critical sections of code are wrapped in a special block that allows the program to continue working in the event of a crash.
Exceptions in PHP
In PHP, exceptions are implemented in following way.
<?php
try {
// protected section of code
} catch (Exception $e) {
// code if an exception occurred
}
Or variant with finally
:
<?php
try {
// protected section of code
} catch (Exception $e) {
// code if an exception occurred
} finally {
// guaranteed execution code
}
In this case, you can use both try/catch/finally
and try/finally
.
It would seem that everything is simple, but as usual in PHP there are nuances.
"Stumbling" for beginners
Let's consider a simple example. There is a function for dividing two numbers.
<?php
function functionOne($a, $b)
{
try {
$r = $a / $b;
} catch (Exception $e) {
$r = 'You cant divide by zero';
}
return $r;
}
echo functionOne(1, 0);
We expect that doing this will output "Can't divide by zero". However, we are actually getting a message from PHP "Warning: Division by zero". That is, the block catch
did not work.
Why is this happening?
Not all errors are exceptions
In PHP, all errors have a type in the form of predefined constants : E_ERROR, E_WARNING, E_NOTICE, etc.
So errors E_WARNING
are not an exceptional situation, since the program can continue its execution further. If after echo functionOne(1, 0);
we place some more code, then PHP will execute it.
This is an important understanding of what exceptions are - tracking down abnormal situations in order to continue further program execution.
That is, when we try to divide a number by zero, then this is just incorrect processing of incoming data, which cannot lead to a complete collapse.
Data processing
PHP is primarily procedural programming, where functions are able to process incoming data on their own. A good example is a function for text, such as strpos()
, which returns not only the position of the occurrence, but also FALSE if there is none.
That is, the point is that in PHP most functions return some value, or at least an error code, instead of crashing the program. Therefore, when programming in PHP, you should try to follow exactly the same logic.
Our example could be rewritten like this:
<?php
function functionTwo($a, $b)
{
if ($b == 0) {
return false;
}
// 'You can't divide by zero';
else {
return $a / $b;
}
}
if ($r = functionTwo(1, 0) !== FALSE) {
echo $r;
} else {
echo 'Error';
}
That is, the function itself must take care of filtering out invalid input. This is especially true if the data is received from the user, such as an uploaded file or a regular form.
How not to do
It is bad practice to throw an exception instead of processing incoming data. In PHP, you can manually throw an exception using throw
.
<?php
function functionThree($a, $b)
{
if ($b === 0) {
throw new Exception('You cant divide by zero');
} else {
return $a / $b;
}
}
try {
echo functionThree(1, 0);
} catch (Exception $e) {
echo $e->getMessage();
}
Here, if $b
equal to zero, an exception is thrown. The problem here is that you only have to use such a function in a try / catch block, which not only complicates the code, but also mixes the application logic with exceptions. Moreover, this example is quite simple: if you dig deeper, then exceptions can be of different types (classes) and their “branching” processing insanely complicates the code.
The right approach
The function must handle its own exceptions.
<?php
function functionFour($a, $b)
{
try {
if ($b === 0) {
throw new Exception('You cant divide by zero');
} else {
return $a / $b;
}
} catch (Exception $e) {
return $e->getMessage();
}
}
echo functionFour(1, 0);
If it $b
is zero, an exception is thrown, which is immediately caught in the catch
. This is, as it were, a combined approach, when the function both checks the data and throws exceptions. Since you can track different situations, you can generate different exceptions. For example, if not a number, but a string or another non-numeric data type is passed to the function, then return either an error message or simply 0.
How to track WARNING
It is important to understand that in PHP errors and exceptions are different things and they work differently. By and large, you can do without exceptions at all, since PHP functions themselves cope well with abnormal situations.
However, PHP has a mechanism for "turning" errors into exceptions. To do this, override the standard error handler with the set_error_handler()
.
<?php
function exception_error_handler($severity, $message, $file, $line)
{
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting
return;
}
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
After that we can call the very first example withafunction()
echo afunction(1, 0);
and get as expected: "You can not divide by zero."
Conclusion
When possible, you should try to use data validation and processing, instead of throwing exceptions. PHP is a fairly developed language where you can check anything for correctness.
If a function throws an exception, it's best if it handles it itself.
It's bad if the function only throws an exception in the hope that "someone" "somewhere" will catch it. And it’s really bad if the logic of a function / application is built on exceptions. This approach negatively affects both the logic of work and the overall amount of code. Understanding it will be problematic.