返回从递归函数PHP找到的所有值

时间:2018-01-09 20:00:25

标签: php recursion

我有一种情况,我需要根据最后一个类别ID建立一个面包屑字符串,所以我需要得到所有的父猫。所以我写了一个递归函数来做这个,但它只返回顶级父对象。

所以基本上如果我的面包屑看起来像这样

All Categories -> Category 1 -> Subcategory 1 -> Subcategory 2

我获得了Subcategory 2的ID,在这种情况下,我需要返回Subcategory 1和Category 1。

    private function get_parent_category( $category_id )
    {
        $category = new ObjCategories();
        $category->get_object( "id=" . $category_id );
        if( !empty( $category->name ) ):
            $parent_category = new ObjCategories();
            $parent_category->get_object( "id=" . $category->parent );
            if( $parent_category->parent == 0 ):
                return $parent_category;
            else:

                $found[] = $this->get_parent_category( $parent_category->id );
                return $found;
            endif;
        else:
            return false;
        endif;
    }

当谈到递归时我是个菜鸟,所以如果答案很明显,那么我道歉。提前致谢

PS-在这个例子中我不能使用echo,我需要捕获数据。

2 个答案:

答案 0 :(得分:1)

IMO有两种很好的方法可以解决这种情况。

选项1

仅将返回值调整为数组,并将每个递归步骤添加到数组的开头或结尾。你的代码看起来像这样(编辑不相关的东西):

private function get_parent_category( $category_id ) {
<shortened>
  if( $parent_category->parent == 0 ):
     return [$parent_category];
  else:
     $found = $this->get_parent_category( $parent_category->id );
     array_unshift( $found , $parent_category ); //or array_push
     return $found;
  endif;
<shortened>    

选项2

或者您可以通过引用传递最终结果并在向下填充它。这看起来像这样;你不需要明确的回报:

private function get_parent_category( $category_id , &$found) {
<shortened>
  if( $parent_category->parent == 0 ):
     $found[] = $parent_category;
  else:
     $this->get_parent_category( $parent_category->id , $found );
     $found[] = $parent_category;
  endif;
<shortened>    

有些人对哪种方式更好有强烈意见,但在我看来,你可以选择你喜欢的方式。

答案 1 :(得分:0)

您的代码存在的问题是结果合并的处理以及小的逻辑错误,这些错误都在代码的那一部分中:

if( $parent_category->parent == 0 ):
    return $parent_category;
else:
    $found[] = $this->get_parent_category( $parent_category->id );
    return $found;
endif;

错误的是,您的$found变量是一个数组,而您的$parent_category变量是一个对象。 因此,您的功能会返回不同的类型。

在行$found[] = $this->get_parent_category( $parent_category->id );中,您递归调用函数,并且固有地使用返回的值作为单个对象,并将其添加到$found数组中,同时函数返回数组中内部调用的所有找到的对象,或单个根。

要解决这种问题,首先应确保您的函数返回的类型始终相同,方法是将根节点作为数组返回,只包含其中的根:

return [$parent_category]; //The same as array($parent_category);

然后,如果当前节点不是根节点,则必须将当前节点添加到数组中并返回数组:

$found = $this->get_parent_category( $parent_category->id );
array_unshift($found, $parent_category);
return $found;

小的逻辑错误是,您要么返回$parent_category,要么使用$parent_category->id调用递归函数。因此,您忘记了当前的$category,它永远不会是您返回的列表的一部分。

要修复此问题,您需要在返回单个对象时返回当前类别而不是父类别,以及将当前类别合并到结果集中,而不是将父项合并到其中。这可以在甚至计算父类别之前完成。

if( $category->parent == 0 ):
    return [$category];
else:
    $parent_category = new ObjCategories();
    $parent_category->get_object( "id=" . $category->parent );
    $found = $this->get_parent_category( $parent_category->id );
    array_unshift($found, $category);
    return $found;
endif;

您的功能将有效。

无论如何它不是很易读,它会调用ObjCategories->get_object方法。您可以通过将代码的递归部分与最初需要调用的部分分开来减少这些调用:

private function get_parent_category( $category_id )
{
    $category = new ObjCategories();
    $category->get_object( "id=" . $category_id );
    if( !empty( $category->name ) ):
        return $this->get_parent_category_recursive($category);
    else:
        return false;
    endif;
}

private function get_parent_category_recursive($category) {
    if( $category->parent == 0 ):
        return [$category];
    endif;

    $parent_category = new ObjCategories();
    $parent_category->get_object( "id=" . $category->parent );

    $found = $this->get_parent_category( $parent_category );
    array_unshift($found, $category);
    return $found;
}

与此类似,调用函数的类别不会再次计算,而是保留以供重用。