How do I use a recursive array iterator to process a multidimensional array?

10,948

Ok, here is a quick something for you to figure out:

$data = array(
    'title'    => 'how to work with iterators',
    'posts' => array(
        array(
        'title'  => 'introduction to iterators',
        'email'  => '[email protected]'
     ), array(
        'title'  => 'extending iterators',
        'email'  => '[email protected]'
     )
));

The main idea is to influence how the Iterator returns the current element. Iterators are stackable, so you should use a RecursiveArrayIterator and wrap it into a RecursiveIteratorIterator. To achieve custom functionality, you can either subclass the RecursiveIteratorIterator (as shown below) or use additional iterators to decorate the RecursiveIteratorIterator:

class PostFormatter extends RecursiveIteratorIterator
{
    public function current()
    {
        $current = parent::current();
        switch($this->key()) {
            case 'email':
                $current = strtolower($current);
                break;
            case 'title':
                $current = ucwords($current);
                break;
            default:
                break;
        }
        return $current;
    }
}

Then you simply foreach over the iterator

$it = new PostFormatter(new RecursiveArrayIterator($data));
foreach($it as $key => $post) {
    echo "$key: $post", PHP_EOL;
}

and get

title: How To Work With Iterators
title: Introduction To Iterators
email: [email protected]
title: Extending Iterators
email: [email protected]

You can try to get the array back from the with iterator_to_array or iterator_apply functions. However, to get the values reapplied to the original array structure, you dont need an iterator:

array_walk_recursive($data, function(&$val, $key) {
    switch($key) {
        case 'title': $val = ucwords($val); break;
        case 'email': $val = strtolower($val); break;
        default: break;
    }
});
print_r($data);

Note: exchange Lambda with Function name when using PHP<5.3

Share:
10,948
bcmcfc
Author by

bcmcfc

JavaScript, JavaScript Does whatever a JavaScript does Is it Java? No, it's a script! Look out! It's JavaScript.

Updated on June 22, 2022

Comments

  • bcmcfc
    bcmcfc almost 2 years

    I'm trying to get something like this working:

    function posts_formatter (&$posts){
        foreach ($posts as $k => $v){
    
            if (is_array($v)){
    
                posts_formatter($v);
    
            }else{
    
                switch (strtolower($k)){
    
                    # make email addresses lowercase
                    case (strpos($k, 'email') !== FALSE):
                        $posts[$k] = strtolower($v);
                        break;
    
                    # make postcodes uppercase
                    case (strpos($k, 'postcode') !== FALSE):
                        $posts[$k] = strtoupper($v);
                        break;
    
                    # capitalize certain things
                    case (strpos($k, 'line1') !== FALSE):
                    case (strpos($k, 'line2') !== FALSE):
                    case (strpos($k, 'line3') !== FALSE):
                    case (strpos($k, 'forename') !== FALSE):
                    case (strpos($k, 'surname') !== FALSE):
                        $posts[$k] = capitalize($v);
                        break;
                }
    
            }
        }
    }
    

    It will correctly go through the array and format the values but I can't get it to return them. I've played around with removing the & from the function declaration and adding a return at the end but it won't do anything.

    Additionally, I'm thinking perhaps using a RecursiveArrayIterator might be the way to go. However, despite the presence of a book right in front of me with a chapter on SPL Iterators its examples are useless towards being able to achieve what I'm trying to. How would I go about implementing one?

    Edit:

    array (
      'user' => 
      array (
        'title' => 'Mr.',
        'forename' => 'lowercase',
        'surname' => 'name',
        'businessName' => 'some dude',
        'telephone' => '07545464646',
        'postcode' => 'wa1 6nj',
        'line1' => 'blergh road',
        'line2' => 'randomLY cApitaLIzed wOrds',
        'line3' => '',
      ),
      'email' => '[email protected]',
      'address' => 
      array (
        'postcode' => 'ab1 1ba',
        'line1' => 'test road',
        'line2' => 'testville',
        'line3' => 'testshire',
      ),
      'date' => '2010-09-30'
    )
    
  • bcmcfc
    bcmcfc over 13 years
    Thanks for your help Gordon. Just one more quick Q- how do I amend it return the processed array with the original array structure intact?
  • bcmcfc
    bcmcfc over 13 years
    Thanks for the detailed explanation.
  • Gordon
    Gordon over 13 years
    @bcmcfc You're welcome. I had to remove the iterator_to_array code because it wouldnt apply the changes to the inner arrays. I am sure you can do it somehow, but right now I cant fiddle with it (time constraints). Sorry.