Julien Deniau

PHP if condition and "falsy" values

In PHP, you can test empty array, empty string or 0 directly in a if statement:

$array = [];

if (!$array) {
    // this will  be executed as $array is empty
}

It's quite useful in general, but it may be harder for static analysis to perform efficient work if you work with a union type with null.

Imagine the following code:

/** @return null|array<string, mixed> */
function getCustomer(string $id): null|array
{
    return random_int(1,2) === 1 ? ['id' => $id] : null;
}

function main(string $id): void {
    $customer = getCustomer($id);

    if ($id) {
        if (null === $customer) {
            throw new \RuntimeException('customer should not be null !');
        }
    } else {
        $customer = ['id' => 'new customer'];
    }

    if (!$customer) {
        // do log something because customer does not exist
    }
}

Static analysis tools, like PHPStan, won't be able to detect that the all if (!$customer) is useless here !

Why ? Because the only case where it will be executed, is when getCustomer returns an empty array, which is never the case.

Try it live: https://phpstan.org/r/adeb5299-2819-4453-9530-0c628d5179be

You have two solutions here to help static analysis:

Declare a better return type for getCustomer

With PHPStan, you can declare array "shapes" like this:

- /** @return null|array<string, mixed> */
+ /** @return null|array{"id": string} */
  function getCustomer(string $id): null|array

This way, PHPStan will know that line 42, $customer will be either null, or a non-empty array, and trigger an error

Try it live: https://phpstan.org/r/579be31c-3e57-47fb-8efb-8fd476eb6160

Compare to null

A probable better solution here would be to compare directly to null on line 20:

- if (!$customer) {
+ if (null === $customer) {

This way, you avoid the "falsy" comparison, as it's the right comparision to do here.

Do not use array for object

This is out of scope, and kind of a troll, but you may want to consider using a proper object instead of an array instead of array shapes 😉.