
One of the core data types in PHP is thearray. Mostly unchanged since the early beginnings of the language. The name "array" is a bit unfortunate, as well as the implementation. It is not really an array.
In fact it is some sort of Frankenstein combination of alist and adictionary, known from other languages. This is quite confusing and can cause unexpected and sometimes nasty effects. Sometimes, it breaks stuff. That happened to me last week. More on that later.
First, to get things clear, let's talk about the difference between lists and dictionaries.
A list, sometimes also known as an array, is like the name suggests, a list of elements of any type. These elements are ordered, and every element has a numeric index, starting with 0.
Example in #"#content-dictionaries" aria-hidden="true" title="Permalink">¶
In Python it's called adictionary, Perl and Ruby call it ahash, in Javascript / JSON it's known as anobject. Which is also rather confusing but that's for another time.
Whatever it's name, a dictionary is a collection ofkey/value pairs. Those key/value pairs don't necessarily a fixed order. The keys are strings, the values can be anything. And every key is unique.
An example in Python:
myDict= {'foo':'bar','boo':'baz'}myElem= myDict['foo']# myElem contains 'bar'myDict['boo']='bla'print(myDict)# output: {'foo': 'bar', 'boo': 'bla'}Once upon a time, the creators of PHP thought it would be a Good Idea to merge lists and dictionaries into one data type, which, to make things worse, they named "array". With the following effects:
Hmmm, I wonder if that could lead to problems. Let's see how this works.
$myArray= ['element 1','element 2','element 3',];print_r($myArray);print_r($myArray[1]);returns as output:
Array( [0] => element 1 [1] => element 2 [2] => element 3)element 2Looks intuitive, this works just like in many other languages. The elements all get assigned a numeric consecutive index, by which they can be accessed.
With key/value pairs it works in a way you would expect too.
$myArray= ['foo'=>'bar','boo'=>'baz',];print_r($myArray);print_r($myArray['boo']);Output:
Array( [foo] => bar [boo] => baz)bazBecause the keys are explicitly defined, there are no auto assigned numerical indexes.
It gets slightly more confusing if we combine lists and dictionaries, which is perfectly fine in PHP:
$myArray= ['foo'=>'bar','blarp',4=>'elem with numeric index',2=>'another elem with lower numeric index','boo'=>'baz',];// add an element to the end of the array$myArray[]='zonk';print_r($myArray);$myArray[3]='three';print_r($myArray);This gives the following output:
Array( [foo] => bar [0] => blarp [4] => elem with numeric index [2] => another elem with lower numeric index [boo] => baz [5] => zonk)Array( [foo] => bar [0] => blarp [4] => elem with numeric index [2] => another elem with lower numeric index [boo] => baz [5] => zonk [3] => three)As a PHP doesn't necessarily have numeric consecutive keys, it isnot always possible to iterate over them this way:
for ($i=0; $i<count($myArray); $i++) { $elem= $myArray[$i];// ...}This would give unexpected behaviour with the array above, andUndefined array key warnings:
blarpPHP Warning: Undefined array key 1 in /home/lennart/Development/php/arrays.php on line 47another elem with lower numeric indexthreeelem with numeric indexzonkPHP Warning: Undefined array key 6 in /home/lennart/Development/php/arrays.php on line 47Therefore, instead of afor loop, it is always better to use aforeach loop:
foreach ($myArrayas $key=> $elem) {// ...}Because that will always work like expected.
So, everything's fine then?
No. The world is bigger than PHP alone. Very often you need to exchange data with other languages or applications. This is very often done using JSON. And then it can be an issue.
JSON has become thede facto standard to exchange data between applications and hosts. Every programming language has functions to decode JSON strings to an internal format, and the oter way around, to encode internal data to JSON strings.
For those conversions, it is essential that they worksymmetric, in other words: if you convert data to JSON, and back, it should still be the same unchanged data.
With a language where an array can be both a list as a dictionary, this will cause some issues.
$json='{"0": "No", "1": "Yes"}';$array=json_decode($json,true);printjson_encode($array);You would expect the original unchanged JSON string, but in fact you get something else:
["No","Yes"]A dictionary suddenly turned into a list! That means that the conversion is not symmetric!
It also happens the other way around:
$array= ['first','second','third',];printjson_encode($array).PHP_EOL;// remove the second elementunset($array[1]);printjson_encode($array).PHP_EOL;Here an array suddenly becomes a dictionary!
["first","second","third"]{"0":"first","2":"third"}What is happening here?
An array in PHP is alist if it has consecutive, numerical keys, starting with 0. If you convert it to JSON, it will also become a list.
In all other cases it actually is adictionary and it will be converted to a JSONobject.
Until very recently there was no separate function to test whether an array is a list or not. But, now with PHP8.1 there finally is the functionarray_is_list. Better late than never, amirite?
But if you use an older PHP version, you could emulate it with thispolyfill:
if (!function_exists('array_is_list')) {functionarray_is_list(array $a):bool {if ($a=== []) {returntrue; }returnarray_keys($a)===range(0,count($a)-1); }}This function can be useful sometimes, but it is not a fix for everything. It couldn't have prevented me from the pit fall from the example above, which is based on a True Event.
$json='{"0": "No", "1": "Yes"}';$array=json_decode($json,true);printjson_encode($array);The above JSON fragment was part of a much bigger JSON document, somewhere in a database. I needed to decode it to PHP to be able to work with it; do some transformations; and then re-encode it to JSON and update the database.
Take note of the second argument forjson_decode. Thetrue makes that the return value is an array, instead of astdClass object. Most of the time I do it like that, because arrays are in general much easier to work with thanstdClass objects.
There are quite a lot ofarray_* functions, but there's almost nothing in that respect for objects. If you want to for example merge two objects, it is easiest to cast them to arrays, throw them througharray_merge amd then cast to objects again if needed. So why even usestdClass objects?
Well, now I know! The JSON dictionary{"0": "No", "1": "Yes"} has consecutive numeric keys! Yes, they are strings, but hey, this is PHP! They are silently cast to integer! So the dictionary changed into a PHP list-like array, and then in a JSON list. Cauusing a form somewhere to break. Thank god for backups.
Arrays can be deceptive in PHP.
They can "act as" alist or adictionary. Most of the time you don't really notice this at all, until you convert them to a format like JSON.
If you are decoding JSON that you need to re-encode back to JSON, it can be a good idea to decode to an object, not an array.
If you want to enforce an array to encode to a JSON list (all array keys will be discarded), use:
json_encode(array_values($array));json_encode((object)$array);
Security is hard. I compiled a list with tips and best practices that may be useful.

It was about time I started writing more about my profession, after all those years. So I started a blog. I built the platform myself. So I wrote a blog post about that.

QR codes are everywhere. Easy to scan with a phone. But what if you want to decode a QR on your laptop instead of your phone, without a camera?

Sublime Text might look more like a text editor than an IDE, but looks can be deceiving. Read why I prefer Sublime Text above other editors and IDEs, and how you can get the most out of it by using the right plugins.