6 weird things in PHP

“PHP is like a box of chocolates, you never know what weird quirk you’re going to get.”

Coding Jester
5 min readApr 5, 2023

Are you ready to take a trip to the wacky, weird, and downright bizarre side of PHP?

PHP is known for its user-friendliness and versatility, but let’s be real — it’s also got some really weird quirks that can leave even seasoned developers scratching their heads.

Buckle up, because we’re about to explore some of the strangest things this scripting language has to offer.

1) in_array() — Magic apperance of items

It might seem that PHP’s in_array() function is breaking the laws of physics. Check out this snippet of code.

$items = ['apple', 'banana', true];

var_dump(in_array('coconut', $items));

// bool(true)

That’s right, PHP thinks that any element you are checking magically appeared when there is a true element in the array. But that’s not the weirdest thing…

Even thou this is already fixed in PHP 8, the next piece of code can cause a headeache event for more seasoned developer using older versions like PHP 7 or PHP 5.

$items = [
'apple' => 1,
'banana' => 0,
'orange' => 1
];

var_dump(in_array('coconut', $items));

// bool(false) in PHP8
// bool(true) in PHP and older

To understand why, you have to know that PHP is looping through the elements a comparing the values one by one. PHP uses loose comparison by default, so as long as any element’s value is 0 or true, the comparison ends like this.

var_dump('coconut' == 0);

// bool(true)

var_dump('coconut' == true);

// bool(true)

To fix this issue, add the third parameter to the in_array() function, which enforces strict comparison.

$items = [
'apple' => 1,
'banana' => 0,
'orange' => 1
];

var_dump(in_array('coconut', $items, true));

// bool(false)

2) Loose vs strict comparison

To expand on the previous point, PHP’s dynamic types and loose comparison can result in a lot of unexpected behaviour.

All of these equal to false.

var_dump(0 == false);
var_dump("0" == false);
var_dump("" == false);
var_dump([] == false);
var_dump(null == false);

// bool(true)
// bool(true)
// bool(true)
// bool(true)
// bool(true)

That alone might not be that weird but…

var_dump(0 == "0");
var_dump(0 == "");
var_dump(0 == []);
var_dump(0 == null);

// bool(true)
// bool(false) in PHP8, bool(true) in PHP7 and older
// bool(false)
// bool(true)

// few more examples:

var_dump("0" == "");
var_dump("0" == []);
var_dump("0" == null);

// bool(false)
// bool(false)
// bool(false)

var_dump("" == []);
var_dump("" == null);

// bool(false)
// bool(true)

var_dump([] == null);

// bool(true)

Same problem exists with true.

var_dump(1 == true);

// bool(true)

var_dump("any string except 0" == true);
var_dump("0" == true);

// bool(true)
// bool(false)

var_dump(['item'] == true);

// bool(true)

Fixing this one is easy, never use “==” , instead use strict comparison with “===” which compares value and its type.

3) @ to silence exceptions

In some older codebases you might find something like this

$values = [
'key' => 'value',
];

...

$result = @$values['another_key'];

The error controll operator “@”, more commonly known as the STFU operator, silences variety of errors prior to PHP 8. Since then, only warnings and notices can be silenced.

As a rule of thumb — never use this, it’s much better and cleaner to wrap parts of code into try-catch blocks and log the exception at least.

$values = [
'key' => 'value',
];

try {
$result = $values['another_key'];
} catch (Throwable $e) {
// log
}

This might depend on your error handler configuration. Check the PHP Documentation for more information.

4) Post-increment/post-decrement — Tardises of operators

To be fair, this is not a quirk, it’s language feature that is available in many programming languages, including C, C++, Java, Python, and others.

Still, it’s good to know what problems it may cause.

// ++$x is called pre-increment

$x = 5;
echo ++$x; // outputs 6

// $x++ is called post-increment

$x = 5;
echo $x++; // outputs 5
echo $x; // outputs 6

The pre-incerement operator does exactly what you expect: first increments the value of the variable by one, then returns the value for further use (in this case, and echo statement).

The post-increment operator can be the source of confusion, as it first returns the value and then increments it by one.

It’s good practise to use only pre-increment, as it is usually sufficient. If necessary, it’s easy to rewrite the code in another way to avoid post-increment.

We, for example, enforce this in our coding standards. Take a look at the Easy Coding Standards, it’s a great tool to have in your toolkit.

5) isset() behaviour — not what you expect with null value

Function isset() might be the thing you want to use, but in many cases, it is not.

Accessing a value from an array by key throws a warning if key does not exist. In the following example, we access the value of an array by key, but the key ‘Olivia’ is not present in the array.

However, it is generally not recommended to use this operator as it can hide other potential issues in the code.

$moneyInThePiggyBank = [
'John' => 10,
'Alex' => 0,
'Jenna' => 69,
];

$oliviasBalance = isset($moneyInThePiggyBank['Olivia']) ? $moneyInThePiggyBank : 0;

echo $oliviasBalance;

// outputs 0

What if, when your piggy bank is empty, there is null, instead of 0? In the next example, we create a record for Olivia, if she does not have her piggy bank yet and credit it with $20. If she does have a record, nothings should happens. Yet, when isset() is used in the condition, something unexpected happens:

$moneyInThePiggyBank = [
'John' => 10,
'Alex' => 0,
'Jenna' => 69,
'Olivia' => null
];

if (!isset($moneyInThePiggyBank['Olivia'])) {
$moneyInThePiggyBank['Olivia'] = 20;
}

echo $moneyInThePiggyBank['Olivia'];

// outputs 20

This is because isset() evaluates whether the variable exists— is declared — and is not null at the same time.

Consider using the array_key_exists() function to check if a key exists in an array. This function can be combined with is_null() to achieve the same behavior as isset(), but it’s less prone to mistakes.

6) empty() — documentation is lying to you

PHP documentation says:

ArrayObject class — This class allows objects to work as arrays.

But not really…

$items = [];
var_dump(empty($items));

// outputs bool(true)

$items = new ArrayObject();
var_dump(empty($items));

// outputs bool(false)

Assuming that ArrayObject take over all array behaviour 1:1 will lead you into sleepless nights and hours of debugging.

Fortunately, there is a straightforward solution to avoid these issues.

$items = [];
var_dump(count($items));

// outputs int(0)

$items = new ArrayObject();
var_dump(count($items));

// outputs int(0)

As we know from points 1 and 2, 0 is same as false for PHP, so you can just rewrite your conditions to count($x) === 0. Plus count() is faster than empty(), this means there is no excuse for using empty() instead of count().

Summary

PHP has its share of peculiarities, such as its loose comparison behavior, which can cause headaches. Some of these are design flaws, but this is not uncommon in programming languages.

With practice, one can learn to avoid PHP’s illogical behavior automatically and despite its quirks, PHP is still a powerful language with many benefits, and there is no reason to dislike it based on its imperfections.

Ultimately, we love PHP and believe you should too.

--

--