Unexpected behavior when accessing non-arrays as arrays

January 20th, 2018

One of the both celebrated and hated features of PHP is its weak typing, and, to be frank, weak typing can give you some issues along the way.

Weak typing means that you do not declare the type of a given variable. For example, in Java (a strongly typed language) you have to write String foo = "bar";, but PHP you can just write $foo = "bar";.

In a strongly typed language you always know what type of variable will be returned from a function or method, but in a weakly typed language you newer know. A lot of people exploit this feature of PHP by have functions that return a list of results on success and FALSE on failure.

Not knowing what is returned means you need to do a lot of checking (or risk assuming your know what you've got). This is where the unexpected behavior comes into play.

If you have a function that you expect to return a list and haven't checked for the FALSE case you might end not even getting an error at the right point in the execution. This could mean several hours of debugging.

Consider the following program snippet:

<?php

$privileges = get_privileges($user);

if ($privileges['is_moderator']) {
  // Add special functionality.
}

If there is an error in the function get_privileges() so that it always returns FALSE the if will never be executed and the "special functionality" will never be added. This error will not show up as an error in any logs. Even with error_reporting set to E_ALL.

This is due to the fact that accessing types such as integers and constants as arrays will silently return NULL. This behavior is know in the PHP community and several bug reports has been submitted going as far back as 2006. It is still relevant in PHP 7.

Below is a small setup that shows which variables will silently return NULL and which will fail.

<?php

error_reporting(E_ALL);

// Constants and integers will silently return NULL.

$foo = NULL;
var_dump($foo['bar']);

$foo = TRUE;
var_dump($foo['bar']);

$foo = 1;
var_dump($foo['bar']);

$foo = 1.2;
var_dump($foo['bar']);

define('MY_VAR', 5);
$foo = MY_VAR;
var_dump($foo['bar']);

// Arrays, Strings, and objects will fail.

$foo = [];
var_dump($foo['bar']);

$foo = "String";
var_dump($foo['bar']);

$foo = stdClass();
var_dump($foo['bar']);

To be fair, this is documented, but now where you might expect. There is a not on the documentation page for Strings that says "Accessing variables of other types (not including arrays or objects implementing the appropriate interfaces) using [] or {} silently returns NULL.".

The take away from this is that when working with weakly typed languages such as PHP you need to check your variables. You might know that the function you just wrote only returns a certain value, but further down the road somebody might make an update that can break that assumption and cause the system to behave unexpectedly.

Categories

IT

Tags

php