Using the Right Types in PHP Means Shipping Fewer Bugs cover image

Using the Right Types in PHP Means Shipping Fewer Bugs

Scott Keck-Warren • June 30, 2025

One of the biggest reasons programming projects turn into a mess isn’t the language itself. It’s the way individual programmers use the language. PHP is what is known as a "loosely typed" language, which means you can pass a string to a function where a number is expected, and the language will try to "make it work." That flexibility makes PHP easy to work with, but it also masks a ton of bugs.

Modern PHP gives you the tools necessary to be more precise about the data your code expects. However, if you're not leaning into strict typing yet, you're probably shipping more bugs than you need to.

Why Type Hints Matter

The code below adds two numbers together and then returns the result.

function add($a, $b)
{
    return $a + $b;
}

You can even do something crazy like add the strings "1" and "2", and because PHP is loosely typed, it will happily do just that.

// output 3
echo add("1", "2");

The issue with this is what happens if one of our parameters doesn't convert to a number?

// Fatal error: Uncaught TypeError: Unsupported operand types: string + string
echo add("1", "");

In this case, we'll get "Uncaught TypeError: Unsupported operand types: string + string," which is not at all what we want our users to experience.

To prevent this, we can declare our types, which will help both your team and any of your Static Code Analysis tools determine exactly what should be passed to the function.

function add(int $a, int $b): int
{
    return $a + $b;
}

Using both scalar (int, string, and bool) and class type hints let you communicate your expectations to both the PHP engine and your teammates. If your function expects a DateTimeImmutable, there’s no guesswork. Anyone reading or using your code knows what to provide.

The Problem with Scalars

While scalar types help communicate what our code is expecting, they can’t cover everything. For example, if you’re passing around email addresses as "plain strings," you’re missing an opportunity to make your code more robust. An email address isn’t just any string because it has a very specific format and purpose, and we can create custom types to make sure our logic is always working with "valid" data.

function sendWelcomeEmail(string $recipient): void {
    // validate in every function call because it's just a string
    if (!filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException("Invalid email address: $recipient");
    }
}

Creating a Custom EmailAddress Type

Creating a small value object to wrap up a concept like an email address adds clarity and prevents misuse. Here’s a simple example:

final class EmailAddress {
    public function __construct(private string $email) {
        if (!filter_var($this->email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException("Invalid email address: $email");
        }
    }

    public function __toString(): string {
        return $this->email;
    }

    public function isEqual(EmailAddress $other): bool {
        return strtolower($this->email) === strtolower((string) $other);
    }
}

Now, instead of passing a raw string, you can pass an EmailAddress object to your functions and not have to :

function sendWelcomeEmail(EmailAddress $recipient): void {
    // Safe to assume it's valid
}

This type of design ensures invalid data doesn’t sneak into places it shouldn’t. You centralize the validation logic in one place, which reduces duplication and increases confidence that your data is clean.

Remember Better Types = Better Code

Using correct and custom types helps you:

It takes a little more effort up front, but it pays off by making your code easier to understand and harder to misuse.

If you're still passing around arrays, strings, and booleans without thinking twice, try defining small, single-purpose classes instead. You'll find that the stricter your code becomes, the fewer errors you'll have to debug later.

This was originally published at https://phpdeveloperstv.substack.com/p/using-the-right-types-in-php-means

Images

Shareable Image