2016-03-21 2 views
2

Сегодня я нашел странное поведение при использовании метода ArrayCollection :: forAll против анонимной функции с рекурсией.ArrayCollection :: forAll с рекурсией

Предпосылки:

У меня есть коллекция Post лиц. Каждый Post содержит набор объектов SocialPost.

Цель: Статус

Набор для всех почтовых и SocialPost субъектам "в ожидании".

Мое решение:

Я думал, что я мог бы использовать довольно простое закрытие, как это:

$setPending = function($_, StatusAwareInterface $post) use (&$setPending) { 
     echo "func entry point reached\r\n"; 
     if ($post instanceof Post) { 
      echo "This is post. SP Count: " . count($post->getSocialPosts()) . "\r\n"; 
      $post->getSocialPosts()->forAll($setPending); 
      $status = Post::STATUS_PENDING; 
     } else { 
      echo "This is SP\r\n"; 
      $status = SocialPost::STATUS_PENDING; 
     } 

     $post->setStatus($status); 
    }; 

    // $post contains 2 Post entities 
    // Each Post entity contains 50+ SocialPost entities 
    $posts->forAll($setPending); 

Результат:

Но выход очень странно. Похоже, forAll использует только первый элемент, а затем ломается:

func entry point reached 
This is post. SP Count: 52 
func entry point reached 
This is SP 

Неужели кто-нибудь видит проблему здесь?

ответ

4

Давайте проверим ArrayCollection source

Док говорит:

 * Applies the given predicate p to all elements of this collection, 
     * returning true, if the predicate yields true for all elements. 

Это может быть misleasing, потому что он не говорит, что если предикат возвращает false, вся функция forAll возвращения falseнемедленно. Давайте посмотрим на источник:

public function forAll(Closure $p) 
{ 
    foreach ($this->elements as $key => $element) { 
     if (! $p($key, $element)) { // <-- here's null converted to false. 
      return false; 
     } 
    } 

    return true; 
} 

Ваша функция ничего, которое null не возвращается. Далее, null преобразуется в false, что приводит к поломке метода forAll перед завершением итерации над вашим ArrayCollection.

В качестве решения вы должны добавить строку

return true; 

на и вашей анонимной функции.

Дополнительное примечание: forAll должны быть понять, как

проверка, если каждый элемент в коллекции соответствует условию

и не

сделать что-то для каждого элемента сбор

Если вы хотите сделать это правильно, вы должны просто сделать цикл foreach.

+0

Да, вы правы. Я использовал этот метод, полагая, что он работает точно так же, как array_walk. Спасибо. – Hast

Смежные вопросы