Exception handling in PHP

Photo by Kelly Sikkema on Unsplash

Exception handling in PHP

PHP Dec 19, 2022

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/finallyand 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 catchdid 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_WARNINGare 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 $bequal 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 $bis 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.

Tags

Anurag Deep

Logical by Mind, Creative by Heart