递归循环 returns 500 内部服务器错误

Recursive looping returns 500 Internal Server Error

在循环中调用递归时出现 500 内部服务器错误。直到那时我才收到 500 错误。

当我删除循环中的递归时,一切正常:

代码:

public function getRecrusiveReferals($userID) {
    $sql = "SELECT user_id, username, refered_by FROM users WHERE refered_by = ?";
    $referals = $this->db->query($sql, $userID);
    $list = $this->buildReferalsTree($referals->result_array());
    return $list;
}

private function buildReferalsTree(array $referals, $parentID = 0) {
    $data = array();

    foreach ($referals as $item) {
        if($item['refered_by']) {
            $children = $this->buildReferalsTree($referals, $parentID);

            if($children) {
                $item['children'] = array();
            }
        }
        $data[] = $item;
    }
    return $data;
}

您的代码有一个无限递归循环,导致您的脚本在递归达到 PHP 为递归深度设置的限制时被 PHP 终止。

使用同一组参数一次又一次地调用此代码:

 $children = $this->buildReferalsTree($referals, $parentID);

为了终止递归函数,应该有一个条件来定义递归何时结束,我在你的代码中没有看到。

您需要为父参数传递一个新值,而不是一遍又一遍地使用相同的值。像这样:

$children = $this->buildReferalsTree($referals, $item['user_id']);

然后在循环中您还需要按父 ID 进行过滤:

if($item['refered_by'] = $parentID)

...所以您只会 link 属于该 ID "children" 的项目。

此外,您的原始调用还应指定 parentID,因为您 select 只有 table:

的特定 referred_by 子集
$list = $this->buildReferalsTree($referals->result_array(), $userID);

然而,这将给出一个无趣的结果,因为您只 selected 具有 相同 referred_by 值的记录,所以没有太多可从中构建一棵树。相反,您可以 select 来自该 table 的所有记录,然后仍然将 $userID 传递给 buildReferalsTree,这样所有其他记录都可用于遵循推荐链。所以这里是 select 所有记录的代码:

$sql = "SELECT user_id, username, refered_by FROM users";
$referals = $this->db->query($sql);

最后,内部 if 块中也存在错误,您当前将空数组分配给 $item['children']。您应该改为分配递归调用的结果,如下所示:

if($children) {
    $item['children'] = $children;
}

综上所述,代码如下所示:

public function getRecrusiveReferals($userID) {
    $sql = "SELECT user_id, username, refered_by FROM users";
    $referals = $this->db->query($sql);
    $list = $this->buildReferalsTree($referals->result_array(), $userID);
    return $list;
}

private function buildReferalsTree(array $referals, $parentID = 0) {
    $data = array();
    foreach ($referals as $item) {
        if ($item['refered_by'] == $parentID) {
            $children = $this->buildReferalsTree($referals, $item['user_id']);
            if($children) {
                $item['children'] = $children;
            }
        }
        $data[] = $item;
    }
    return $data;
}

如果您的数据在引用方面具有循环,这仍然可以提供无限递归。鉴于推荐的含义,但情况不应如此。

正如 Jay Rajput 所说,那里有无限递归。我认为调用

$children = $this->buildReferalsTree($referals, $parentID);

不应传递 $referals,而是另一个基于 $item 的 'refered_by' 元素构建的数组。 所以基本上你需要创建另一个私有方法,提取新的 $referals。 您必须仍然意识到这段代码不会容易出错,如果两个项目相互引用,您仍然会以无限递归结束。

您要完成的任务是一个相当大的挑战,尤其是当您使用关系数据库时。您肯定想看看关系数据库中的 'nested set' 概念。