PHP Arrays
PHP Arrays
PHP Arrays
So far we've looked at the basic variables types such as strings and integers,
as well as a variety of functions you can use to manipulate these data types.
Beyond the basic data types are arrays and objects, which take a little bit more
work in order for you to take advantage of them properly. More importantly,
arrays take a solid understanding of functions before you try to use them, which
is why they are separated here! As mentioned, objects are covered exclusively in
their own chapter - this chapter is dedicated to the topic of arrays.
Reading arrays
Manipulating arrays
Saving arrays
Chapter contents
First steps
array array ( [mixed ...])
int count ( mixed var [, int mode])
bool print_r ( mixed expression [, bool return])
void var_dump ( mixed expression [, mixed expression [, mixed ...]])
mixed var_export ( mixed expression [, bool return])
PHP has built-in support for arrays of data, and there are two ways you can
create an array: using the array function, or using a special operator, [ ].
Before we look at how arrays work, there are two key things you need to understand
before you continue:
An array is a normal PHP variable like any others, but it works like a
container - you can put other variables inside it
On line one we see the most basic way to create an array, the array() function.
The array() function takes a minimum of one parameter (and a maximum of as many
as you want), and returns an array containing those variables. That's right
- $myarray now contains all three variables. Line two contains a new
function, count(), that returns the number of elements consisting in the array
passed to it as its only parameter - in the example we pass in my $myarray,
then store the number of elements (three) in $size.
Author's Note: The array() function actually allows you to have a trailing
comma after the last element, eg: array("Apples", "Oranges", "Pears",). This is
rarely used in hand-written code, but it can make generating code much easier.
Line three contains another new function, print_r(). This takes just one
parameter, but it outputs detailed information about a variable, such as it is
type, length, and contents. In the case of arrays, print_r() iteratively
outputs all elements inside the array - it is a good way to see how arrays
work.
Array
(
[0] => Apples
[1] => Oranges
[2] => Pears
)
As you can see, there are our three variables - Apples is at index 0 in the
array (signified by "[0]=>"), Oranges is at index 1 in the array, and Pears is
at index 2 in the array. Note that if you are running your scripts through a
web browser as opposed to from the command-line, you may find it help to put a
HTML <pre> tag before your print_r() calls, as this will format them for easier
reading.
Using the proper array terminology defined earlier, the 0, 1, and 2 indices are
the keys of each element, the "Apples", "Oranges", and "Pears" are the values of
each element, and the key and the value considered together are the elements
themselves.
Note that you can provide a second parameter to print_r(), which, if set to
true, will make print_r() pass its output back as its return value, and not
print anything out. To achieve the same output using this method, we would need
to alter the script to this:
<?php
$myarray = array("Apples", "Oranges", "Pears");
$size = count($myarray);
$output = print_r($myarray, true);
print $output;
?>
You can store whatever you like as values in an array, and you can mix values
also. For example: array("Foo", 1, 9.995, "bar",$somevar). You can also put
arrays inside arrays, but we will be getting on to that later.
array(3) {
[0]=>
string(6) "Apples"
[1]=>
string(7) "Oranges"
[2]=>
string(5) "Pears"
}
In there you can see var_dump() has told us that the array has three values,
and also prints out the lengths of each of the strings. For teaching
purposes, var_dump() is better as it shows the variable sizes, however you will
probably want to use print_r() in your own work.
array (
0 => 'Apples',
1 => 'Oranges',
2 => 'Pears',
)
Note there is an extra comma after the last element, however this is ignored by
PHP and you can copy and paste that information directly into your own scripts,
like this:
<?php
$foo = array (
0 => 'Apples',
1 => 'Oranges',
2 => 'Pears',
);
?>
<?php
$myarray = array("Apples", "Oranges", "Pears");
$myarray = ["Apples", "Oranges", "Pears"];
?>
Associative arrays
As well as choosing individual values, you can also choose your keys - in the
fruits code above we just specify values, but we could have specified keys along
with them, like this:
<?php
$myarray = array("a"=>"Apples", "b"=>"Oranges", "c"=>"Pears");
var_dump($myarray);
?>
array(3) {
["a"]=>
string(6) "Apples"
["b"]=>
string(7) "Oranges"
["c"]=>
string(5) "Pears"
}
As expected, our 0, 1, and 2 element keys have been replaced with a, b, and c,
but we could equally have used "Foo", "Bar", and "Baz", or even variables or
other arrays to act as the keys. Specifying your own keys produces what is
called an associative array - you associate a specific key with a specific
value. Most associative arrays use strings as keys, but do not be afraid to try
more advanced things out.
The one exception here is floating-point numbers: these make very poor array
indexes. The problem lies in the fact that PHP converts them to integers before
they are used, which essentially rounds them down. So, the following code will
create an array with just one element in:
<?php
$array[1.5] = "foo";
$array[1.6] = "bar";
?>
The first line will read 1.5 as the key, round it down to 1, then store "foo" at
index 1. The second line will read 1.6 as the key, also round it down to 1, then
store "bar" at index 1, overwriting "foo". If you really want to use floating-
point numbers as your keys, pass them in as strings, like this:
<?php
$array["1.5"] = "foo";
$array["1.6"] = "foo";
var_dump($array);
?>
array(2) {
["1.5"]=>
string(3) "foo"
["1.6"]=>
string(3) "foo"
}
This time the floating-point numbers have not been rounded down or converted at
all, because PHP is using them as strings. The same solution applies to reading
values out from an associative array with floating-point keys - you must always
specify the key as a string.
If you do not specify a key, as in the first example, PHP will just assign
incrementing numbers starting with 0. However, these numbers cannot be guaranteed
to exist within the array in any given order, or even to exist at all - they are
just key values themselves. For example, an array may have keys 0, 1, 2, 5, 3,
6, 7. That is, it can have its keys out of order or entirely missing. As a result,
code like this should generally be avoided:
<?php
for ($i = 0; $i < count($array); ++$i) {
print $array[$i];
}
?>
However, there is a quick and easy way to accomplish the same thing: a foreach
loop, which itself has two versions. The easiest way to use foreach looks like
this:
foreach($array as $val) {
print $val;
}
Here the array $array is looped through and its values are extracted into $val.
In this situation, the array keys are ignored completely, which usually makes
most sense when they have been auto-generated (i.e. 0, 1, 2, 3, etc).
The second way to use foreach does allow you to extract keys, and looks like
this:
<?php
while (list($var, $val) = each($array)) {
print "$var is $val\n";
}
?>
List() is a function that does the opposite of array() - it takes an array, and
converts it into individual variables. Each() takes an array as its parameter,
and returns the current key and value in that array before advancing the array
cursor. "Array cursor" is the technical term for the element of an array that
is currently being read. All arrays have a cursor, and you can freely move it
around - it is used in the while loop above, where we need to iterate through
an array. To start with, each() will return the first element, then the second
element, then the third, and so on, until it finds there are no elements left,
in which case it will return false and end the loop.
The meaning of that first line is "get the current element in the array, and
assign its key to $var and its value to $val, then advance the array cursor.
There is a lot more detail on array cursors later.
Generally speaking, using foreach loops is the most optimised way to loop
through an array, and is also the easiest to read. In practice, however, you
will find foreach loops and list()/each() loops in about equal proportions,
despite the latter option being slower. The key difference between the two is
that foreach automatically starts at the front of the array,
whereas list()/each() does not.
<?php
$array[] = "Foo";
$array[] = "Bar";
$array[] = "Baz";
var_dump($array);
?>
That should work in precisely the same as using the array() function, except it
is much more flexible - we can add to the array whenever we want to. When it
comes to working with non-default indices, we can just place our key inside the
brackets, like this:
<?php
$array["a"] = "Foo";
$array["b"] = "Bar";
$array["c"] = "Baz";
var_dump($array);
?>
<?php
function dofoo() {
$array["a"] = "Foo";
$array["b"] = "Bar";
$array["c"] = "Baz";
return $array;
}
$foo = dofoo();
?>
Without returning an array, the only other way to pass data back to the calling
script is by accepting parameters by reference and changing them inside the
function. Passing arrays by reference like this is generally preferred as it is
less of a hack, and also frees up your return value for some a true/false to
check whether the function was successful.
Array-specific functions
Although arrays are great by themselves, their real usefulness only comes out
when you use special array functions to manipulate your data - this was why we
had to cover functions before arrays.
There are quite a few array functions all doing a variety of things, and you need
not learn them all - your best bet is to give them all a try so that you at least
know how they work, then get back to working on normal code. You'll soon learn
what works for you best!
There are three key functions that handle the comparison of two arrays to
create a new array, and they work in much the same way - they take a minimum of
two arrays as parameters (we will call them $arr1 and $arr2), and return an
array for a result.
The difference is that array_diff() returns a new array containing all the
values of $arr1 that do not exist in $arr2, array_intersect()returns a new array
containing all the values of $arr1 that do exist in $arr2,
and array_merge() just combines the two arrays. These three functions work well
as a team, and allow you to construct combined arrays out of individual arrays.
<?php
$toppings1 = array("Pepperoni", "Cheese", "Anchovies", "Tomatoes");
$toppings2 = array("Ham", "Cheese", "Peppers");
$inttoppings = array_intersect($toppings1, $toppings2);
$difftoppings = array_diff($toppings1, $toppings2);
$bothtoppings = array_merge($toppings1, $toppings2);
var_dump($inttoppings);
var_dump($difftoppings);
var_dump($bothtoppings);
?>
As you can see, there are two arrays of pizza toppings, and they both share
cheese as a value. Here is what that script outputs:
Author's Note: The + operator in PHP is overloaded so that you can use it to merge arrays, eg
$array3 = $array1 + $array2, but will ignore any key clashes, and so is quite confusing to use
unless you have unique keys.
$toppings2 = array_unique($toppings2);
Try the example code again, this time removing the duplicate Cheese values
from $bothtoppings.
<?php
function endswithy($value) {
return (substr($value, -1) == 'y');
}
$people = array("Johnny", "Timmy", "Bobby", "Sam", "Tammy", "Danny", "Joe");
$withy = array_filter($people, "endswithy");
var_dump($withy);
?>
In this script we have an array of people, most of which have a name ending
with "y". However, several do not, and for one reason or another we want to
have a list of people whose names ends in "y", so array_filter() is used. The
function endswithy() will return true if the last letter of each array value
ends with a y, otherwise false. By passing that as the second parameter
to array_filter(), it will be called once for every array element, passing in
the value of the element as the parameter to endswithy(), where it is checked
for a "y" at the end.
<?php
$Wales = 'Swansea';
$capitalcities['England'] = 'London';
$capitalcities['Scotland'] = 'Edinburgh';
$capitalcities['Wales'] = 'Cardiff';
extract($capitalcities);
print $Wales;
?>
After calling extract, the "England", "Scotland", and "Wales" keys become
variables in their own right ($England, $Scotland, and$Wales), with their values
set to "London", "Edinburgh", and "Cardiff" respectively. By
default, extract() will overwrite any existing variables, meaning that $Wales's
original value of "Swansea" will be overwritten with "Cardiff".
This behaviour can be altered using the second parameter, and averted using the
third parameter. Parameter two takes a special constant value that allows you to
decide how values will be treated if there is an existing variable, and parameter
three allows you to prefix each extract variable with a special string. Here are
the possible values of the second parameter:
The last option, EXTR_REFS, can either be used on its own or in combination with
others using the bitwise OR operator |.
Here are some examples based upon the $capitalcities array from the previous
example:
<?php
$Wales = 'Swansea';
extract($capitalcities, EXTR_SKIP);
print $Wales;
print $Scotland;
extract($capitalcities, EXTR_PREFIX_SAME, "country");
print $Wales;
print $country_England;
extract($capitalcities, EXTR_PREFIX_ALL, "country");
?>
On line one we pre-set $Wales to be a value so that you can clearly see how the
second parameter works. On line two we callextract() using two parameters, with
EXTR_SKIP as parameter two so that our $Wales will not be overwritten. However,
as you will be able to see if you run the script, $England and $Scotland were
set.
On line five we use EXTR_PREFIX_SAME, which will extract variables and use the
third parameter as a prefix if it finds any collisions. As we
set $Wales ourselves and our previous call
to extract() created $England and $Scotland, all our variables will need to be
prefixed. As you can see on line six, $Wales is still set to "Swansea", and on
line seven we have our prefixed variable$country_England. Note that PHP places
an underscore _ after your prefix to make the variable easy to read.
The in_array() function does precisely what you might think - if you pass it a
value and an array it will return true if the value is in the array, otherwise
false. This following example show it in action:
<?php
$needle = "Sam";
$haystack = array("Johnny", "Timmy", "Bobby", "Sam", "Tammy", "Danny", "Joe");
if (in_array($needle, $haystack)) {
print "$needle is in the array!\n";
} else {
print "$needle is not in the array\n";
}
?>
If you have ever used the C++ Standard Template Library, you will know how useful
the deque (double-ended queue, pronounced "deck") type is. If you have never used
STL, or C++ for that matter, a deque allows you to store elements in an array-
like structure, then work with either the very first element or the very last
element. This might not sound useful, after all we've already seen that PHP lets
you read from any variable in an array at any time, so why would it be good to
work with only the first and last elements?
Well, using what you know already, how would you insert a variable at the very
first position in your array? Or how would you read the first element and remove
it from the array? It would be tricky, for sure - and that's where the deque
principle comes in.
Array_shift() takes an array as its only parameter, and returns the value from
the front of the array while also removing it from the array. Consider this
script:
<?php
$names = array("Johnny", "Timmy", "Bobby", "Sam", "Tammy", "Danny", "Joe");
$firstname = array_shift($names);
var_dump($names);
?>
If you run that script, you will see that $firstname is set to "Johnny", and the
array $names now only has the values Timmy, Bobby, Sam, Tammy, Danny, and Joe -
Johnny gets removed. To remove an element from the end of an array (as opposed
to the start), there is also array_pop(), which works in the same way
as array_shift(). Both these functions also have
opposites, array_unshift() andarray_push(), which place an element into an
array at the start or at the end respectively. This next script should clear up
any confusion:
<?php
$names = array("Johnny", "Timmy", "Bobby", "Sam", "Tammy", "Danny", "Joe");
$firstname = array_shift($names);
// First element of $names is now Timmy; last is Joe
array_push($names, $firstname);
// first is Timmy; last is now Johnny
$firstname = array_pop($names);
// first is Timmy; last is Joe again
array_unshift($names, $firstname);
// first is Johnny, last is Joe
var_dump($names);
?>
Extracting the first and last variable from an array is a very popular task, so
try to keep these functions in the back of your mind.
The array_flip() function takes just one parameter, an array, and exchanges all
the keys in that array with their matching values, returning the new, flipped
array. You can see how it works in this script:
<?php
$capitalcities['England'] = 'London';
$capitalcities['Scotland'] = 'Edinburgh';
$capitalcities['Wales'] = 'Cardiff';
$flippedcities = array_flip($capitalcities);
var_dump($flippedcities);
?>
array(3) {
["London"]=>
string(7) "England"
["Edinburgh"]=>
string(8) "Scotland"
["Cardiff"]=>
string(5) "Wales"
}
As you can see, "London", "Edinburgh", and "Cardiff" are the keys in the array
now, with "England", "Scotland", and "Wales" as the values - simple.
Sorting arrays
bool asort ( array input [, int sort_flags])
bool ksort ( array input [, int sort_flags])
bool arsort ( array input [, int sort_flags])
bool krsort ( array input [, int sort_flags])
<?php
$capitalcities['England'] = 'London';
$capitalcities['Wales'] = 'Cardiff';
$capitalcities['Scotland'] = 'Edinburgh';
ksort($capitalcities);
var_dump($capitalcities);
asort($capitalcities);
var_dump($capitalcities);
?>
Note that both ksort() and asort() work by reference, directly changing the
value you pass in - the return value is either true or false, depending on
whether the sorting was successful. The first var_dump will output the array
sorted by key, therefore it will be England, Scotland, then Wales. The second
var_dump will output the array sorted by values, therefore it will be Cardiff,
Edinburgh, London.
These two functions also have companions, arsort() and krsort(), which reverse
sort the array and reverse sort the array by key respectively.
There is one particular situation that may catch you out when sorting arrays,
and that's when you have not assigned your own keys and are accessing the data
by index. Consider this next script:
<?php
$capitalcities[] = 'London';
$capitalcities[] = 'Cardiff';
$capitalcities[] = 'Edinburgh';
var_dump($capitalcities);
asort($capitalcities);
var_dump($capitalcities);
?>
This time the keys are being assigned by PHP, so 0 will be London, 1 will be
Cardiff, and 2 will be Edinburgh. When sorted, however, the keys 0, 1, and 2
stay with the values, which means the second var_dump() call will output this:
array(3) {
[1]=>
string(7) "Cardiff"
[2]=>
string(9) "Edinburgh"
[0]=>
string(6) "London"
}
Now, if you were to try to access that using a for loop and use $capitalcities[$i],
you would find the data in the original order. This is because even though
"London" is last in the array, it still uses the key 0 and will therefore be
accessed first.
There are two ways to solve this problem. First, you can use a foreach loop to
access the array in its natural order; this is the preferred method of
accessing arrays anyway, and you should use it if you can. Alternatively, you
can use the array_values() function to effectively reset the array keys.
By default, the sort functions sort so that 2 comes before 10. While this might
be obvious, consider how a string sort would compare 2 and 10 - it would work
character by character, which means it would compare 2 against 1 and therefore
put 10 before 2. Sometimes this is the desired behaviour, and so you can pass a
second parameter to the sort functions to specify how you want the values sorted,
like this:
<?php
$array["1"] = "someval1";
$array["2"] = "someval2";
$array["3"] = "someval3";
$array["10"] = "someval4";
$array["100"] = "someval5";
$array["20"] = "someval6";
$array["200"] = "someval7";
$array["30"] = "someval8";
$array["300"] = "someval9";
var_dump($array);
ksort($array, SORT_STRING);
var_dump($array);
?>
If you want to force a strictly numeric sort, you can pass SORT_NUMERIC as the
second parameter.
Array_keys() and array_values() are very closely related functions: the former
returns an array of all the keys in an array, and the latter returns an array
of all the values in an array. For example, consider you had an array with user
IDs as keys and usernames as values, you could use array_keys() to generate an
array where the values were the keys. Try this following example out:
<?php
$users[923] = 'TelRev';
$users[100] = 'Skellington';
$users[1202] = 'CapnBlack';
$userids = array_keys($users);
var_dump($userids);
?>
After execution, $userids will be an array of user IDs, as you will see when
the var_dump() function outputs $userids to the screen.
There are two other parameters that can be passed to array_keys(), which are,
in order, a value to match, and whether to perform strict matching. These two
are there to allow you to filter your array keys - if you specify "tennis", for
example, then the only keys that array_keys() will return are the ones that
have the value "tennis". By default this is done by checking each key's value
with the == operator (is equal to), however if you specify 1 as the third
parameter the check will be done with === (is identical to).
<?php
$users[923] = 'TelRev';
$users[100] = 'Skellington';
$users[1202] = 'CapnBlack';
$userids = array_keys($users, "TelRev");
var_dump($userids);
?>
This time the $userids array will only contain one element, with a value of 923,
as the script filters by value "TelRev".
Moving on, the usefulness of the array_values() function may at first not be
apparent - after all, why would you want the values of a new array to be set to
the values of an old array? This all boils down to how numerical arrays are
indexed. If you use the array operator [] to assign variables to an array, PHP
will use 0, 1, 2, etc as the keys. If you then sort the array using a function
such asasort(), which keeps the keys intact, the array's keys will be out of
order because asort() sorts by value, not by key.
However, using the array_values() function makes PHP create a new array where
the indexes are recreated and the values are copied from the old array,
essentially making it renumber the array elements.
<?php
$array[] = "Hello";
$array[] = "World";
$array[] = "Foo";
$array[] = "Bar";
$array[] = "Baz";
var_dump($array);
asort($array);
var_dump($array);
var_dump(array_values($array));
?>
The first var_dump() prints the array out in its original ordering. The second
prints it out ordered by the values - the keys will be jumbled up, however. The
final call to var_dump() uses array_values() to create a new array, and you
should see that the jumbled up keys have been re-ordered. Here's how it looked
on my screen:
array(5) { [0]=> string(5) "Hello" [1]=> string(5) "World" [2]=> string(3) "Foo" [3]=>
string(3) "Bar" [4]=> string(3) "Baz" }
array(5) { [3]=> string(3) "Bar" [4]=> string(3) "Baz" [2]=> string(3) "Foo" [0]=>
string(5) "Hello" [1]=> string(5) "World" }
array(5) { [0]=> string(3) "Bar" [1]=> string(3) "Baz" [2]=> string(3) "Foo" [3]=>
string(5) "Hello" [4]=> string(5) "World" }
You should use array_values() when you want to re-order an array's indexes
either because they are jumbled up or because they have holes in, but you can
also use it to convert an associative array with strings as the indexes to a
plain numerical array.
Very often you will find yourself not wanting to read from your array in a
strictly ordered fashion, and in this situation you need to make use of
either shuffle() or array_rand().
Shuffle() takes the entire array and randomises the position of the elements in
there. In earlier versions of PHP the shuffle()algorithm was not very good,
leading the "randomisation" to be quite weak, however that problem is now
fixed.
<?php
$natural_born_killers = array("lions", "tigers", "bears", "kittens");
shuffle($natural_born_killers);
var_dump($natural_born_killers);
?>
One major drawback to using shuffle() is that it mangles your array keys. This
is unavoidable sadly, and you need to live with it when you use shuffle(). Note
that shuffle uses its parameter by reference - it returns true, but shuffles up
the parameter you pass to it.
If you want to pick out just one random value from an array, you can
use array_rand() - it takes an array to read from, then returns one random key
from inside there. The advantage to array_rand() is that it leaves the original
array intact - you can use the random key returned to grab the related value
from the array, but other than that the original array is left untouched.
Array_rand() has an optional second parameter that allows you to specify the
number of elements you would like returned. These are each chosen randomly from
the array, and are not necessarily returned in any particular order.
Before I show you an example, you need to be aware of the following attributes
of array_rand():
It returns the keys in your array. If these aren't specified, the default
integer indexes are used. To get the value out of the array, just look up
the value at the key.
If you ask for one random element, or do not specify parameter two, you
will get a standard variable back.
If you ask for more than one random element, you will receive an array of
variables back.
If you ask for more random elements than there are in the array you will
get an error
Array_rand() will not return duplicate elements if you request more than
one random element
If you want to read most or all of the elements from your array in a
random order, use a mass-randomiser like shuffle() - it is faster.
<?php
$natural_born_killers = array("lions", "tigers", "bears", "kittens");
var_dump(array_rand($natural_born_killers, 2));
?>
How would you code that in PHP? The obvious answer is code like this:
<?php
$questions = array(1, 2, 3, 4, 5, ..., 38, 39, 40);
$questions = shuffle($questions);
?>
The slightly smarter programmer might save themselves some typing with more
intelligent code like this:
<?php
for ($i = 1; $i <= 40; ++$i) {
$questions[] = $i;
}
shuffle($questions);
?>
However, that's still not the most efficient way of doing it. Instead, PHP has
a special range() function that allows you to create an array of numbers
between a low value (parameter one) and a high value (parameter two). So the
best way to write the script is this:
<?php
$questions = range(1,40);
$questions = shuffle($questions);
?>
As you can see, range() returns the array between 1 and 40 (inclusive), ordered
sequentially. This is then passed through shuffle() to get the random question
numbers - perfect!
There are a three other tricks to range() that you should be aware of. Firstly,
it has a third parameter that allows you specify a step amount in the range.
For example:
Although the step parameter should always be positive, the second trick is that
if your low parameter (parameter one) is higher than your high parameter
(parameter two), you get an array counting down, like this:
Finally, you can also use range() to create arrays of characters, like this:
For creating these simple kinds of arrays, there is nothing better than
using range() - it is very fast, very easy to read, and the step parameter can
save you extra work.
Multidimensional arrays
One key advantage to arrays is that they can contain other arrays. Currently our
arrays just hold standard, non-array variables, which makes them one-dimensional.
However, by switching to a two-dimensional array - each element holds an array
as its value, and each element in the child array holds a non-array variable -
we can store much more information. Consider this script:
<?php
$capitalcities['England'] = array("Capital"=>"London", "Population"=>40000000,
"NationalSport"=>"Cricket");
$capitalcities['Wales'] = array("Capital"=>"Cardiff", "Population"=>5000000,
"NationalSport"=>"Rugby");
$capitalcities['Scotland'] = array("Capital"=>"Edinburgh", "Population"=>8000000,
"NationalSport"=>"Football");
var_dump($capitalcities);
?>
This time we're creating our $capitalcities array elements as before, but we're
using an array for each value. Each child array has three elements: Capital,
Population, and NationalSport. At the end there is a var_dump() for the parent
array, which should really show you how helpful var_dump() is. Here is the
output:
array(3) {
["England"]=>
array(3) {
["Capital"]=>
string(6) "London"
["Population"]=>
int(40000000)
["NationalSport"]=>
string(7) "Cricket"
}
["Wales"]=>
array(3) {
["Capital"]=>
string(7) "Cardiff"
["Population"]=>
int(5000000)
["NationalSport"]=>
string(5) "Rugby"
}
["Scotland"]=>
array(3) {
["Capital"]=>
string(9) "Edinburgh"
["Population"]=>
int(8000000)
["NationalSport"]=>
string(8) "Football"
}
}
As you can see, not only does var_dump() recurse into child arrays to output
their contents to, but it indents all the output according to the array level.
Author's Note: The count() function has a helpful second parameter that, when
set to 1, makes count() perform a recursive count. The difference is that if
you pass in a multidimensional array, count() will count all the elements in
the first array, then go into the first array element and count all the
elements in there, and go into any elements in there, etc, etc. For example,
the$capitalcities array above has three elements in, so if you do not use the
second parameter to count() you will get 3 back. However, if you pass in 1 for
the second parameter, you will get 12: three for the first-level elements
("England", "Wales", "Scotland"), and three each for the variables inside those
elements ("Capital", "Population", "NationalSport").
If you're just learning PHP, I would recommend skipping this section entirely - using
foreach loops is easier, faster and cleaner.
Earlier on I mentioned that each array has a "cursor", which you can think of as
an arrow pointing to the next array element in line to be operated on. It is the
array cursor that allows code like while (list($var, $val) = each($array)) to
work - each moves forward the array cursor of its parameter each time it is
called, until it eventually finds itself at the end of the array, and so returns
false, ending the loop.
<?php
$array = array("Foo", "Bar", "Baz");
print "First time...\n";
while (list($var, $val) = each($array)) {
print "$var is $val\n";
}
The chances are, that piece of code will not do what you expect, because it
will not print out the contents of $array the second time around. The reason for
the strange result is because each() does not move the array cursor back to the
first element when you first call it - it just picks up from where the cursor
was. As a result, after our first while loop, the cursor is right at the end of
the array, so that when it comes to the second while loop, the each() function
returns false immediately because it is pointing to the last item in the array.
It is in situations like this where you need to set the position of the array
cursor forcibly, and there are four functions to help you
out: reset(), end(), next(), and prev(). They all take just one parameter, the
array to work with, and return a value from the array.
Reset() rewinds its array parameter's cursor to the first element, then returns
the value of that element, whereas end() set the array cursor to the last
element, and returns that value. Next() and prev() both move the cursor pointer
forward or backward one element respectively, returning the value of the
element now pointed to. If any of the four functions cannot return a value (if
there are no elements in the array, or if the array cursor has gone past the
last element), they will return false. As such, you can use them all in loops
if you want.
<?php
$array = array("Foo", "Bar", "Baz", "Wom", "Bat");
print end($array);
while($val = prev($array)) {
print $val;
}
?>
Note that we print the output of end(), because it sets the array cursor to
point at "Bat", and prev() will shift the array cursor back one to "Wom",
meaning that "Bat" would otherwise not be printed out.
Holes in arrays
Consider this script:
<?php
$array["a"] = "Foo";
$array["b"] = "";
$array["c"] = "Baz";
$array["d"] = "Wom";
print end($array);
while($val = prev($array)) {
print $val;
}
?>
The way around this is the same way around the problems inherent to using for
loops with arrays, and that is to use each() to properly iterate through your
arrays, as each() will cope fine with empty variables and unknown keys.
Therefore, the script should have been written as this:
<?php
$array["a"] = "Foo";
$array["b"] = "";
$array["c"] = "Baz";
$array["d"] = "Wom";
Arrays in strings
Very often you will want to use an array directly inside a string using code
something like this:
<?php
$myarray['foo'] = "bar";
print "This is from an array: $myarray['foo']\n";
?>
Sadly, that won't work - PHP will consider $myarray to be a variable by itself
and consider the ['foo'] part as a normal string that it should tack on to the
end of the value of $myarray. The way around this is to use braces { and }
around the variable, which is how you tell PHP that you are passing it an array
to read from. This next snippet is the right way to do things:
<?php
$myarray['foo'] = "bar";
print "This is from an array: {$myarray['foo']}\n";
?>
Saving arrays
string serialize ( mixed value)
mixed unserialize ( string input)
string urlencode ( string text)
string urldecode ( string encoded)
As arrays are complex data types, you cannot see their contents directly. If
you try printing out the value of an array, you will see PHP just outputs
"Array", which means that passing the value of an array through a link requires
a lot of work. Luckily, PHP comes to the rescue with four functions that do all
the hard work for you: serialize(), unserialize(), urlencode(),
and urldecode().
Urlencode() and urldecode() also work in tandem, and convert the string that is
sent to them as their only parameter into a version that is safe to be passed
across the web. All characters that aren't letters and numbers get converted
into web-safe codes that can be converted back into the original text
using urldecode().
Passing arrays across pages is best done using urlencode() and urldecode(),
however you should consider using them both on any data you pass across the
web, just to make sure there are no incompatible characters in there.
<?php
$array["a"] = "Foo";
$array["b"] = "Bar";
$array["c"] = "Baz";
$array["d"] = "Wom";
$str = serialize($array);
$strenc = urlencode($str);
print $str . "\n";
print $strenc . "\n";
?>
That will output two lines (the second of which I've forced to wrap so that it
appears properly!):
a:4:{s:1:"a";s:3:"Foo";s:1:"b";s:3:"Bar";s:1:"c";s:3:"Baz";s:1:"d";s:3:"Wom";}
a%3A4%3A%7Bs%3A1%3A%22a%22%3Bs%3A3%3A%22Foo%22%3Bs%3A1%3A%22b%22%3Bs%3A0%3A%22%22%3Bs%
3A1%3A%22c%22%3Bs%3A3%3A%22Baz%22%3Bs%3A1%3A%22d%22%3Bs%3A3%3A%22Wom%22%3B%7D
The first is the direct, serialize()d output of our array, and you can see how
it works by looking through the text inside there. The second line contains
the urlencode()d serialize()d array, and is very hard to read. Despite being
hard to read, the latter is wholly web safe, and there much better to use.
Once your array is in text form, you can do with it as you please. To return
back to the original array, it needs to be urldecode()d, then unserialize()d,
like this:
<?php
$arr = unserialize(urldecode($strenc));
var_dump($arr);
?>
Author's Note: If you want to transfer binary data over the web, you should
use rawurlencode() and rawurldecode() as opposed
to urlencode() and urldecode(), as the raw versions are binary-safe.
Summary
Arrays are a great way of storing variables that natural collect together,
such as colours, days of the week, members of a team, or items in a shopping
basket.
Use the extract() function to pull all items out of an array and into the
global scope, as it is faster and also easier to work with.
Exercises
1. What is the difference between an associative array and a multidimensional
array?
o a) Once ever
3. To safely pass an array over the web, what is the correct sequence of
function calls:
o a) shuffle()
o b) mt_shuffle()
o d) Neither a) nor b)
6. Which of the following statements are true about arrays that have a hole
(e.g. it has keys 0, 1, 2, and 4):
o a) You can use foreach to loop through the array and ignore the hole
Further reading
The shuffle() and array_rand() functions are fairly good at providing
pseudo-random information, but the whole topic of randomisation is much
more massive and complex than you may realise. If you are interested in
learning more about randomisation, I suggest you learn from the best:
Donald Knuth's "Art of Computer Programming, Volume 2: Seminumerical
Algorithms" should do the trick, if your maths is up to scratch.