PHPBuilder - PHP Arrays: Advanced Iteration and Manipulation



RSS Twitter
Articles Php Functions

PHP Arrays: Advanced Iteration and Manipulation

by: W.J. Gilmore
|
February 27, 2012

Sporting more than 70 native array-related functions, PHP's array manipulation capabilities have long been one of the language's most attractive features. Whether you want to reverse an array, determine whether a value exists, convert an array to a string, or calculate the array size, completing the task is as simple as executing the appropriate function. There are however many array-related tasks which ask a bit more of the developer than merely knowing what part of the manual one needs to consult. Many such tasks require a somewhat more in-depth understanding of the native features, or are possible only when a bit of imagination is applied to the problem.

Sorting a Multidimensional Associative Array

PHP offers several array sorting functions, among them sort(), ksort(), and asort(). But one feature seemingly missing is the ability to sort a multidimensional associative array such as the following:

Array
(
  [0] => Array
    (
      [name] => chess
      [price] => 12.99
    )

  [1] => Array
    (
      [name] => checkers
      [price] => 9.99
    )

  [2] => Array
    (
      [name] => backgammon
      [price] => 29.99
    )
)

To sort the array by ascending price, you'll need to create a function which compares each price, and then pass that function as a callback to the usort() function:

function comparePrice($priceA, $priceB)
{
 return $priceA['price'] - $priceB['price'];
}

usort($games, 'comparePrice');

After executing this snippet, the $games array will be sorted like this:

Array
(
  [0] => Array
    (
      [name] => checkers
      [price] => 9.99
    )

  [1] => Array
    (
      [name] => chess
      [price] => 12.99
    )

  [2] => Array
    (
      [name] => backgammon
      [price] => 29.99
    )
)

To sort the array in descending order, just update the comparePrice() function to subtract $priceA['price'] from $priceB['price'].

Iterating Recursively Over an Array

PHP's while and foreach statements are the most common solution for iterating over an array. But how might you iterate over all contents of an array which looks like this:

Array
(
  [0] => Array
    (
      [name] => Board
      [games] => Array
        (
          [0] => Array
            (
              [name] => chess
              [price] => 12.99
            )

          [1] => Array
            (
              [name] => checkers
              [price] => 9.99
            )
        )
    )
)

The Standard PHP Library's collection of iterators not only standardize the syntax used to iterate over a variety of different data structures (such as the file system and database results), but also takes much of the guesswork out of figuring out how to iterate over an unknown number of nested arrays. You can use the RecursiveArrayIterator to easily iterate over the above results:

$iterator = new RecursiveArrayIterator($games); 
iterator_apply($iterator, 'navigateArray', array($iterator)); 

function navigateArray($iterator) { 
    
  while ($iterator->valid()) { 

    if ($iterator->hasChildren()) { 
      navigateArray($iterator->getChildren()); 
    } 
    else { 
      printf("%s: %s
", $iterator->key(), $iterator->current()); } $iterator->next(); } }

Executing this snippet produces the following results:

name: Board
name: chess
price: 12.99
name: checkers
price: 9.99

Filtering Associative Array Results

Suppose you were handed the following array but only wanted to work with the games having a list price of less than $11.99:

Array
(
  [0] => Array
    (
      [name] => checkers
      [price] => 9.99
    )

  [1] => Array
    (
      [name] => chess
      [price] => 12.99
    )

  [2] => Array
    (
      [name] => backgammon
      [price] => 29.99
    )
)

Use the array_reduce() function to create an array consisting solely of game names:

function filterGames($game)
{
  return ($game['price'] < 11.99);
}

$names = array_filter($games, 'filterGames');

The array_filter() function will filter out all array entries not satisfying a particular condition as determined by the callback function (which in this example is filterGames()). Any game having a price of less than $11.99 is identified as a desirable entry, whereas the others are tossed aside. The outcome of executing this snippet follows:

Array
(
  [1] => Array
    (
      [name] => checkers
      [price] => 9.99
    )
)

Converting an Object to an Array

The question of how to convert an object to an array often arises, and the answer is easier than many would think; just typecast the object! Consider the following example:

class Game {
  public $name;
  public $price;
}

$game = new Game();
$game->name = 'chess';
$game->price = 12.99;

print_r(array($game));

Executing this example produces the following output:

Array
(
[0] => Game Object
  (
    [name] => chess
    [price] => 12.99
  )
)

However, converting an object to an array has numerous initially unexpected side effects. For instance, the above snippet works fine if the properties are all public, but private properties are returned somewhat differently. Consider the following example:

class Game {
  public $name;
  private $_price;

  public function setPrice($price)
  {
    $this->_price = $price;
  }

}

$game = new Game();
$game->name = 'chess';
$game->setPrice(12.99);

print_r(array($game));

Executing this snippet produces the following output:

Array
(
[0] => Game Object
  (
    [name] => chess
    [_price:Game:private] => 12.99
  )
)

As you can see, the private price property name is changed in the result in order to make clear the property is private.

Sorting an Array "Naturally"

Without a doubt one of the most confusing aspects of sorting an array is PHP's unexpected approach to sorting alphanumeric strings. For instance, suppose you've expanded the gaming business into video games, and were creating a website which output dynamically generated video game covers in a certain order. The array looks like this:

Array
(
  [0] => madden2011.png
  [1] => madden2011-1.png
  [2] => madden2011-2.png
  [3] => madden2012.png
)

How would you expect this array to be sorted by PHP? Surprisingly, when using sort() the output looks like this:

Array ( [0] => madden2011-1.png [1] => madden2011-2.png [2] => madden2011.png [3] => madden2012.png )

You can resolve this issue using the natsort() function, which takes into account a "human"-oriented sorting perspective:

$prices = array('madden2011.png', 'madden2011-1.png', 
                'madden2011-2.png', 'madden2012.png');

sort($prices);

Execute this snippet and the array will look like this:

Array
(
  [1] => madden2011-1.png
  [2] => madden2011-2.png
  [0] => madden2011.png
  [3] => madden2012.png
)

Where to From Here?

PHP's array iteration and manipulation capabilities are indeed profound, however the answers to some of the more advanced problems aren't always so apparent; hopefully this article leaves you thinking about some of the approaches and behaviors you can exploit to sort even the most complex data structure!

Jason Gilmore is founder of the publishing, training, and consulting firm WJGilmore.com. He is the author of several popular books, including "Easy PHP Websites with the Zend Framework", "Easy PayPal with PHP", and "Beginning PHP and MySQL, Fourth Edition". Follow him on Twitter at @wjgilmore.

Comment and Contribute

Your comment has been submitted and is pending approval.

Author:
W.J. Gilmore

Comment:



Comment:

(Maximum characters: 1200). You have characters left.