【问题标题】:PHP: Recursively get children of parentPHP:递归获取父母的孩子
【发布时间】:2010-02-28 21:12:50
【问题描述】:

我有一个函数可以从我的数据库中获取父母的所有孩子的 ID。所以,如果我查找 id 7,它可能会返回一个包含 5、6 和 10 的数组。然后我想要做的是递归地找到这些返回的 id 的孩子,依此类推,直到孩子的最终深度。

我试图编写一个函数来执行此操作,但我对递归感到困惑。

function getChildren($parent_id) {
    $tree = Array();
    $tree_string;
    if (!empty($parent_id)) {
        // getOneLevel() returns a one-dimentional array of child ids
        $tree = $this->getOneLevel($parent_id);
        foreach ($tree as $key => $val) {
            $ids = $this->getChildren($val);
            array_push($tree, $ids);
            //$tree[] = $this->getChildren($val);
            $tree_string .= implode(',', $tree);
        }

        return $tree_string;
    } else {
        return $tree;
    }

}//end getChildren()

函数运行后,我希望它返回一个包含所有找到的子 ID 的一维数组。

【问题讨论】:

    标签: php recursion parent-child children


    【解决方案1】:

    这对我来说很好:

    function getOneLevel($catId){
        $query=mysql_query("SELECT categoryId FROM categories WHERE categoryMasterId='".$catId."'");
        $cat_id=array();
        if(mysql_num_rows($query)>0){
            while($result=mysql_fetch_assoc($query)){
                $cat_id[]=$result['categoryId'];
            }
        }   
        return $cat_id;
    }
    
    function getChildren($parent_id, $tree_string=array()) {
        $tree = array();
        // getOneLevel() returns a one-dimensional array of child ids        
        $tree = $this->getOneLevel($parent_id);     
        if(count($tree)>0 && is_array($tree)){      
            $tree_string=array_merge($tree_string,$tree);
        }
        foreach ($tree as $key => $val) {
            $this->getChildren($val, &$tree_string);
        }   
        return $tree_string;
    }
    

    拨打getChildren(yourid); 然后它将返回给定节点/父节点的完整子节点数组。

    【讨论】:

    • 这很好。您可能需要将这两个都包装在课堂上。我还在右下方插入代码after $tree = $this->getOneLevel($parent_id); ` foreach ($tree as $branch => $branch_string) { if (in_array($branch_string, $tree_string)) { unset($tree[$branch]); } }`这看起来不对,我该如何评论代码示例?
    【解决方案2】:

    嵌套集模型代替邻接表模型


    我可以建议您将节点存储在 NSM 下而不是 ALM 下的数据库中吗?

    请注意,使用 ALM(这是您正在使用的)获取子节点非常困难,但这是可能的,但需要额外的工作。如果您使用嵌套集模型选择子节点或所有节点,甚至查找所有节点的深度,都可以在单个 SQL 查询中完成。

    我希望这对您如何解决您的问题有所启发,如果您在项目开发中还很年轻,那么现在切换将为您以后省去很多麻烦。

    【讨论】:

    • 使用邻接表模型,是否容易更新/移动父节点?
    • 不,更新 ALM 表需要很多查询。大约 6~ 取决于您优化查询的能力。当你选择时,所有的好处都得到了。然后,您可以只做一个查询,而不是做 4 个查询来选择深度、孩子、父母等。因此,如果您选择的内容多于插入和更新的内容,则应使用 ALM imho。
    • 不就是反过来吗?使用嵌套集,通过选择和排序与每个节点关联的左侧值,很容易检索完整的树(或树的任何子集)。有关更多信息,请参阅dev.mysql.com/tech-resources/articles/hierarchical-data.html(特定于 MySQL,但如果需要,应该可以轻松移植到另一个 RDBMS)。
    • 对不起,是的,你是对的。情况恰恰相反。我将编辑。 :) 我总是把它们弄混。
    • 我想通了,现在我坚持使用 NMS,因为我真正需要的是这个功能来做很多事情。
    【解决方案3】:

    而不是array_push($tree, $ids); 尝试$tree = array_merge($tree, $ids);。杀死$tree_string .= implode(',', $tree);return $tree。 (一次)

    function getChildren($parent_id) {
        $tree = Array();
        if (!empty($parent_id)) {
            $tree = $this->getOneLevel($parent_id);
            foreach ($tree as $key => $val) {
                $ids = $this->getChildren($val);
                a$tree = array_merge($tree, $ids);
            }
        }
        return $tree;
    }
    

    【讨论】:

      最近更新 更多