PHP:从递归函数返回一个数组

时间:2016-12-09 17:32:20

标签: php recursion

我有一个像这样的数组:

SimpleXMLElement Object
(
    [BrowseNodes] => SimpleXMLElement Object
        (
            [BrowseNode] => SimpleXMLElement Object
                (
                    [BrowseNodeId] => 969391031
                    [Name] => Bambine e ragazze
                    [Children] => SimpleXMLElement Object
                        (
                            [BrowseNode] => Array
                                (
                                    [0] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 969394031
                                            [Name] => Calze
                                        )

                                    [1] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635837031
                                            [Name] => Felpe
                                        )

                                    [2] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635838031
                                            [Name] => Giacche
                                        )

                                    [3] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635839031
                                            [Name] => Guanti da giocatore
                                        )

                                    [4] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 969392031
                                            [Name] => Maglie
                                        )

                                    [5] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 4351854031
                                            [Name] => Maglie per tifosi
                                        )

                                    [6] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635840031
                                            [Name] => Magliette da portiere
                                        )

                                    [7] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 969393031
                                            [Name] => Pantaloncini
                                        )

                                    [8] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635841031
                                            [Name] => Pantaloncini da portiere
                                        )

                                    [9] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635842031
                                            [Name] => Pantaloni
                                        )

                                    [10] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635843031
                                            [Name] => Tute da ginnastica
                                        )

                                )

                        )

                    [Ancestors] => SimpleXMLElement Object
                        (
                            [BrowseNode] => SimpleXMLElement Object
                                (
                                    [BrowseNodeId] => 969386031
                                    [Name] => Abbigliamento
                                    [Ancestors] => SimpleXMLElement Object
                                        (
                                            [BrowseNode] => SimpleXMLElement Object
                                                (
                                                    [BrowseNodeId] => 937258031
                                                    [Name] => Calcio
                                                    [Ancestors] => SimpleXMLElement Object
                                                        (
                                                            [BrowseNode] => SimpleXMLElement Object
                                                                (
                                                                    [BrowseNodeId] => 524013031
                                                                    [Name] => Categorie
                                                                    [IsCategoryRoot] => 1
                                                                    [Ancestors] => SimpleXMLElement Object
                                                                        (
                                                                            [BrowseNode] => SimpleXMLElement Object
                                                                                (
                                                                                    [BrowseNodeId] => 524012031
                                                                                    [Name] => Sport e tempo libero
                                                                                )

                                                                        )

                                                                )

                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

我需要做的是使用Anchestors构建面包屑。列表末尾的那个应该是第一个。所以,作为一个例子:

Sport e tempo libero>分类> CALCIO ...

我试图以这种方式用函数迭代xml但没有成功:

    $rec=$result->BrowseNodes->BrowseNode->Ancestors->BrowseNode;

    $bread=array();
    function recursive($r)
    {
        do{
            $bread[]=$r->BrowseNodeId;
            recursive($r->Ancestors->BrowseNode);
        }while(isset($r->Ancestors));
        $bread=array_reverse($bread);
        return $bread;
    }

    print_r(recursive($rec));

我在stackoverflow上发现了类似的东西,但没有任何建议帮助我解决这个问题。

5 个答案:

答案 0 :(得分:9)

要使用输出创建递归函数,您需要三件事:

  1. 用于保存当前位置的变量或参数,即代码中的$r。 你有这个权利。
  2. 保存结果的变量或参数,您没有。 起初它似乎是$bread,但它没有任何值,因为每次调用recursive()时它都是空的。 一个简单的解决方案是在函数内声明它为global
  3. if语句,用于检查您没有的停止条件。 相反,您的代码中有一个do-while循环。
  4. 所以,你有两个错误。 根据您的代码并尽可能少地修改它,这是正确的代码:

    $rec = $result->BrowseNodes->BrowseNode->Ancestors->BrowseNode;
    
    $bread = array();
    function recursive($r)
    {
        global $bread;
    
        $bread[] = strval($r->BrowseNodeId);
    
        if(isset($r->Ancestors)){
            return recursive($r->Ancestors->BrowseNode);
        }else{
            return array_reverse($bread);
        }
    }
    
    print_r(recursive($rec));
    

    你去。

    更新:我同意@FlameStorm,如果可能,应该避免使用global。 我还收到了使用static的建议,但它引入了一个错误。 因此,如果您不确定如何使用它,我建议您不要使用static

    这是改进的代码:

    $rec = $result->BrowseNodes->BrowseNode->Ancestors->BrowseNode;
    
    function recursive($r)
    {
        if(isset($r->Ancestors))
            $bread = recursive($r->Ancestors->BrowseNode);
    
        $bread[] = strval($r->BrowseNodeId);
        return $bread;
    }
    
    print_r(recursive($rec));
    

    不再需要函数外部的$bread变量。 此外,未使用globalstatic

答案 1 :(得分:4)

SimpleXMLElement不是数组。您可以将其转换为数组,但PHP提供了专门针对此案例的迭代器SimpleXMLIterator

由于你有一个递归结构,我的建议是用RecursiveIteratorIterator展平它。假设您的数据位于名为$xml的变量中,您的解决方案可能如下所示:

$xmlIterator  = new SimpleXMLIterator($xml->Ancestors);
$flatIterator = new RecursiveIteratorIterator($xmlIterator, RecursiveIteratorIterator::SELF_FIRST);

$breadcrumb = [];
foreach($flatIterator as $node) {
    $breadcrumb[] = $node['Name'];
}

$breadcrumb = array_reverse($breadcrumb);

答案 2 :(得分:0)

<?php
$sxe = new SimpleXMLElement("BrowseNodes.xml", NULL, TRUE);

// prepare a String for the SimpleXMLIterator.
// The SimpleXMLIterator expects:
// "A well-formed XML string or the path or URL to an XML document"
// therefore get the xml-string by calling asXML() on the 
$partitialXMLString = $sxe->BrowseNodes->BrowseNode->Ancestors->asXML();

$recursiveIterator = new RecursiveIteratorIterator(
        new SimpleXMLIterator($partitialXMLString), 
        RecursiveIteratorIterator::CHILD_FIRST
);

// if you need only the names
$name = array();

// if you need the links to something
$link = array();
$baseUrl = "http://example.com/BrowseNodeId/";

// if you need just the nodes in an array, and create the output later from it
// $xmlNode = array()

foreach($recursiveIterator as $node) {
    if (false == empty($node->Name)){
        $name[] = (string) $node->Name;
        $link[] = "<a href='" . $baseUrl . $node->BrowseNodeId . "'>" .  $node->Name . "</a>\n";

        // for later processing
        // $xmlNode[] = $node; 
    }
}

// Add the top BrowseNode->Name, from the node, where the First "Ancestors" is.
// This could be done also in the loop, when looping over all elements, 
// by adding conditions in order to differentiate between Children and Ancestors
// But this is more readable, and for your structure should be enough.
$firstNode = $sxe->BrowseNodes->BrowseNode;
$name[] = $firstNode->Name;
$link[] = "<a href='" . $baseUrl . $firstNode->BrowseNodeId . "'>" .  $firstNode->Name . "</a>\n";
// $xmlNode[] = $firstNode;

//output the path (child first)
// &gt; is  >
echo implode(' &gt; ', $name); 

echo "<br>\n";
//output the links (child first)
echo implode(' &gt; ', $link);

浏览器中的输出:

  

Sport e tempo libero&gt;分类&gt; Calcio&gt; Abbigliamento&gt; Bambine e ragazze
  Sport e tempo libero&gt;分类&gt; Calcio&gt; Abbigliamento&gt; Bambine e ragazze
  (带链接的第二行)

生成的html代码:

Sport e tempo libero &gt; Categorie &gt; Calcio &gt; Abbigliamento &gt; Bambine e ragazze<br>
<a href='http://example.com/BrowseNodeId/524012031'>Sport e tempo libero</a>
 &gt; <a href='http://example.com/BrowseNodeId/524013031'>Categorie</a>
 &gt; <a href='http://example.com/BrowseNodeId/937258031'>Calcio</a>
 &gt; <a href='http://example.com/BrowseNodeId/969386031'>Abbigliamento</a>
 &gt; <a href='http://example.com/BrowseNodeId/969391031'>Bambine e ragazze</a>

答案 3 :(得分:0)

修正了上面的一个答案 - 如果可以的话,你应该避免使用global

所以,代码将是

$rec = $result->BrowseNodes->BrowseNode->Ancestors->BrowseNode;

function recursive($r)
{
    $breads = [strval($r->BrowseNodeId)];

    if (isset($r->Ancestors)) {
        $breads = array_merge(recursive($r->Ancestors->BrowseNode), $breads);
    }

    return $breads;
}

$breadcrumbs = recursive($rec); // You got it.
print_r($breadcrumbs);

答案 4 :(得分:0)

或者,您可以使用$ _SESSION从递归中获取数据

function start(){
$_SESSION['new1']=[];
$this->recursive($array);
$newVal = $_SESSION['new1'];
$_SESSION['new1']=[];
return $newVal;
}

function recursive($array){
...
$_SESSION['new1'][] = $val;
...
}