Как использовать итератор рекурсивного массива для обработки многомерного массива? - PullRequest
8 голосов
/ 30 сентября 2010

Я пытаюсь заставить что-то вроде этого работать:

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;
            }

        }
    }
}

Он будет правильно проходить через массив и форматировать значения, но я не могу его вернуть. Я поиграл с удалением & из объявления функции и добавлением возврата в конце, но это ничего не даст.

Кроме того, я думаю, что, возможно, использование RecursiveArrayIterator может быть подходящим вариантом. Однако, несмотря на то, что передо мной стоит книга с главой об итераторах SPL, ее примеры бесполезны для достижения цели, которую я пытаюсь достичь. Как бы я пошел о реализации одного?

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' => 'CAPITALIZED@BLERGH.com',
  'address' => 
  array (
    'postcode' => 'ab1 1ba',
    'line1' => 'test road',
    'line2' => 'testville',
    'line3' => 'testshire',
  ),
  'date' => '2010-09-30'
)

1 Ответ

19 голосов
/ 30 сентября 2010

Хорошо, вот вам кое-что, чтобы вы могли выяснить:

$data = array(
    'title'    => 'how to work with iterators',
    'posts' => array(
        array(
        'title'  => 'introduction to iterators',
        'email'  => 'JohnDoe@example.com'
     ), array(
        'title'  => 'extending iterators',
        'email'  => 'JaneDoe@example.com'
     )
));

Основная идея заключается в том, чтобы повлиять на то, как Iterator возвращает элемент current. Итераторы являются наращиваемыми, поэтому вы должны использовать RecursiveArrayIterator и заключить его в RecursiveIteratorIterator. Для достижения пользовательских функций вы можете либо создать подкласс RecursiveIteratorIterator (как показано ниже), либо использовать дополнительные итераторы для украшения 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;
    }
}

Тогда вы просто foreach через итератор

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

и получите

title: How To Work With Iterators
title: Introduction To Iterators
email: johndoe@example.com
title: Extending Iterators
email: janedoe@example.com

Вы можете попытаться вернуть массив из функций iterator_to_array или iterator_apply. Однако для повторного применения значений к исходной структуре массива итератор не требуется:

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);

Примечание: меняйте лямбда на имя функции при использовании PHP <5.3 </p>

...