$title =

Nothing great ever came that easy

;

$content = [

The title can be odd at first glance but it fits perfectly when we are talking about PHP. Though PHP is a low-level learning curve language, although, beyond that, it can be more verbose than even Java indeed, in this post I mention that this beloved language has been my most interesting adventure when I say anything about defensive programming.

I’ve separated a few examples I found while reading some project documentation and realized how great they are so I decided to write this post to share that awesome knowledge. This will help you to decide better and act as a safe-wise developer.

As of now, we’re going to dive into a few examples when a pretty good code can be very tricky, and particularly easy to fail:

public function get_email(array $data): string
{
    return $data['email'];
}

Pretty simple right? A handy function to get the array data without having to navigate or even access it directly, and if you do the minimal you will document that function can raise an Undefined index notice, and then you’re fine, huh? But upfront you might say, it can be improved but you’re unsure how to do it. Let’s try something.

Problems I can see just looking into the code:

  1. Let’s get rid of this crappy documentation 🤢 the solve the Undefined index notice issue with a more elegant solution;
  2. Also, there is no assurance that the email key will be a string, even though we’ve indicated that the return type hint for the method should be a string.

On the second version of the code, we’ve addressed the aforementioned issues and provided a better development experience for those consuming this method. In case we couldn’t find the email key or if it is empty we return an empty string (falsy result). Though this is better, but it is still having a few improvement points, let’s see:

public function get_email(array $data): string
{
    return (string) $data['email'] ?? '';
}

We have introduced the ?? null coalescing operator to ask “does email exist?” If so, use that value, otherwise, fall back to the provided value (which in this case is an empty string). This operator is handy for a defensive programming approach.

As mentioned we can improve this code, since casting to a string value isn’t a great solution if we get an undesired value. Minor, it’ll cast the empty string to a string, which is redundant. Furthermore, and perhaps most importantly, it’s not really guarding against what could be a real bug.

The function below would be my choice, as it let’s space to add a log function giving a better investigation method without having to debug the function we would try to understand why the given data have some weirdness:

public function get_email(array $data): string
{
    // make sure `email` exists and that it's already a string
    if (isset($data['email']) && is_string($data['email'])) {
        return $data['email'];
    }

    return ''; // or whatever fallback string you want, and/or log that something weird happened here
}

The above code probably seems very verbose for what you want to be doing, but it’s extremely safe and will never throw notices or errors. It’s also much easier for someone else to look at and be confident about what it’s doing.  Also, gives space for a log message which could be helpful to understand something odd happened.

This last one follows a bit different approach when you are sure the execution has to be stopped/handled if something weird happens. That inverses the intention of the code we wrote. Instead of ensuring that $data['email'] exists and is of the correct type, and having a fallback if not, we’ve written the internals of the method such that it’ll throw an exception if the given data is known to be incorrect. Throw exceptions in a scenario like that is not my first choice as I prefer to let the client decide what to do but sometimes it is necessary based on your business logic:

public function get_email(array $data): string
{
    // throw an exception if we get a $data array that is malformed
    if (empty($data['email']) || !is_string($data['email']) {
        throw new \InvalidArgumentException('$data must contain a non-zero string for the key "email"');
    }

    // if we got this far, then everything should be cool
    return $data['email'];
}

This post is part of a series I’m writing, so I hope to have comments here. Please let me know if you would like to see more examples and perhaps would like to change anything.

Have fun 😉

];

$date =

;

$category =

;

$author =

;

Discover more from Rafael Meneses

Subscribe now to keep reading and get access to the full archive.

Continue reading