具有递归的ArrayCollection :: forAll

时间:2016-03-21 20:27:25

标签: php symfony recursion doctrine closures

今天,我对使用递归的匿名函数使用ArrayCollection :: forAll方法时发现了奇怪的行为。

前提条件:

我有一组Post个实体。每个Post都包含SocialPost个实体的集合。

目标

将所有Post和SocialPost实体的状态设置为" pending"。

我的解决方案:

我认为我可以使用非常简单的闭包,就像这样:

    $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

有人在这里看到问题吗?

1 个答案:

答案 0 :(得分:4)

让我们检查 ArrayCollection source

Doc说:

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

这可能会产生误解,因为它没有说明如果谓词返回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循环。