PHP递归函数获取n代x父级


PHP Recursive Function to get n generations of x parents

我需要返回从一个人开始的'x'代数(作为$generations参数传递)的家庭数据(父母、兄弟姐妹和伴侣)(作为$id参数传递)。我不能假设有两个父母,这个特殊的家谱模型必须考虑到父母的动态数量(考虑到生物学和收养关系)。我认为我的递归是向后的,但我不知道怎么做。

下面的代码触发了我的基本子句5次,每一代一次,因为$generation不是针对每一组父级,而是针对每一个父级减少1。我想要的是,当获取初始人的所有父母的"x"代数时,基子句($generations==0)只触发一次。

public function fetchRelationships($id = 1, $generations = 5, $relationships = array())
{
  $perId = $id;
  if ($generations == 0) {
            return $relationships;
        } else {
            $parents = $this->fetchParents($perId);
            $relationships[$perId]['parents'] = $parents;
            $relationships[$perId]['partners'] = $this->fetchPartners($perId);
            if (!empty($parents)) {
                --$generations;
                foreach ($parents as $parentRel) {
                    $parent = $parentRel->getPer2();
                    $pid = $parent->getId();
                    $relationships[$perId]['siblings'][$pid] = $this->fetchSiblings($perId, $pid);
                    $perId = $pid;
                    $relationships[$perId] = $this->fetchRelationships($perId, $generations, $relationships);
                }
            }
            return $relationships;
        }
}

方法fetchPartners、fetchParents和fetchSiblings只获取匹配的实体。所以我不会把它们粘贴在这里。假设有2个父代,5代,每代有2个母代,那么返回数组应该包含62个元素,并且只有在填充了这62个元素后才应该触发基子句。

提前感谢您的帮助。

-----------编辑--------

删除fetchSiblings和fetchPartners代码进行重写,使其更易于阅读:

public function fetchRelationships($id = 1, $generations = 5, $relationships = array())
{
  $perId = $id;
  if ($generations == 0) {
            return $relationships;
        } else {
            $parents = $this->fetchParents($perId);
            $relationships[$perId]['parents'] = $parents;
            if (!empty($parents)) {
                --$generations;
                foreach ($parents as $parentRel) {
                    $perId = $parentRel->getPer2()->getId();
                    $relationships[$perId] = $this->fetchRelationships($perId, $generations, $relationships);
                }
            }
            return $relationships;
        }
}

Garr Godfrey说得对$当它到达每个分支的末尾时,代数将等于零。因此,只要有分支,你就会多次点击"基本子句"。在foreach ($parents as $parentRel)循环中,为每个父级调用fetchRelationships。这是两个分支,所以您将有两个对"基本子句"的调用。然后,对于他们的每个父母,你将有另外两个对"基本条款"的调用,依此类推…

此外,您正在来回传递relationships,使其元素引用回自身。我意识到你只是在努力保留信息,但实际上你在创造很多不必要的自我参考。

试试这个

public function fetchRelationships($id = 1, $generations = 5)
{
  $perId = $id;
  $relationships = array();
  if ($generations == 0) {
            return $relationships;
        } else {
            $parents = $this->fetchParents($perId);
            $relationships[$perId]['parents'] = $parents;
            if (!empty($parents)) {
                --$generations;
                foreach ($parents as $parentRel) {
                    $perId = $parentRel->getPer2()->getId();
                    $relationships[$perId] = $this->fetchRelationships($perId, $generations);
                }
            }
            return $relationships;
        }
}

您仍然会多次命中基本子句,但这并不重要。

你可能会想"但我会丢失$relationships中的一些数据",但你不会。所有这些都来自递归返回。

如果您要从数据库中提取它,您是否考虑过让查询为您完成所有的工作?

不确定你需要如何堆叠或排除数据,但这里有一种方法:

<?php   
class TreeMember {
    public $id;
    // All three should return something like:
    // array( $id1 => $obj1, $id2 => $obj2 )
    // and would be based on $this->$id
    public function fetchParents(){ return array(); }
    public function fetchPartners(){ return array(); };
    public function fetchSiblings(){ return array(); }; 
    public function fetchRelationships($generations = 5)
    {
        // If no more to go
        if ($generations == 0) { return; }   
        $branch = array();
        $branch['parents'] = $this->fetchParents();
        $branch['partners'] = $this->fetchPartners();
        $branch['partners'] = $this->fetchSiblings();   
        // Logic
        $generations--;
        foreach($branch as $tmType, $tmArr)
        {
            foreach($tmArr as $tmId => $tmObj)
            {
                $branch[$tmType][$tmId] =
                    $mObj->fetchRelationships
                    (
                        $generations
                    )
                );
        }); 
        return array($this->id => $branch);
    }
}