PHP递归函数+数组引用=头痛

时间:2009-11-09 13:35:29

标签: php recursion scope pass-by-reference

我有一个有趣的问题。问题的基础是我最后一次迭代的数组引用没有 似乎“坚持”,如果你愿意的话。一点背景:我为页面层次设计了一个非常简单的数据结构 看起来像这样:

,1,2,3-&GT,4 GT;,&5,6,7 LT;<,8

翻译:忘记烦人的领导逗号。第1,2,3页和第1页8是顶级页面ID,4是子页面3('>'表示更深层次移动),5,6和& 7,是4的子页面。

更易读的格式如下:

1
2
3
- 4
- - 5
- - 6
- - 7
8

不要问我为什么这样做。我还没有想出一种更简单的方法来使用javascript生成结构并通过Web表单发布。

问题是在整个递归函数中一切都很顺利,但我在调用函数中丢失了第8页。我怀疑我对递归,变量引用和变量范围的某些元素有误,这已经变成了难题。

预期输出(在函数的最后一次调用中正常工作):

Array
(
[1] => Array
    (
    )

[2] => Array
    (
    )

[3] => Array
    (
        [4] => Array
            (
                [5] => Array
                    (
                    )

                [6] => Array
                    (
                    )

                [7] => Array
                    (
                    )

            )

    )

[8] => Array
    (
    )

)

实际输出(循环外):

Array
(
[1] => Array
    (
    )

[2] => Array
    (
    )

[3] => Array
    (
        [4] => Array
            (
                [5] => Array
                    (
                    )

                [6] => Array
                    (
                    )

                [7] => Array
                    (
                    )

            )

    )

)

有什么想法吗?

[编辑]:我删除了一些剩余的self :: reference ...

CODE:

<?php
// recursive string in this format: (,\d+)*[>|<]?
//   ,      = leading comma
//   n,n+1  = comma-delimited list of page_ids
//   >      = indicates the next step in our depth-first approach
//   <      = indicates we're done with that set of children. back it up.
function parse_page_orders($page_orders, &$cur_page, &$trail)
{
    // #1 matches our comma-led, comma-delimited list of page id's
    // #2 matches our next step--forward or backward
    preg_match('/([,\d+]*)([>|<])?/', $page_orders, $matches);

    // remove this section of the page_orders variable so we can get on with our lives
    $page_orders = str_replace($matches[0], '', $page_orders);

    // #1: get the list of page ids and add it to the current page item
    $p = explode(',', $matches[1]);
    // start at 1 to skip the empty element at the beginning
    for ($i=1; $i<count($p); $i++)
    {
        $cur_page[$p[$i]] = array();
    }
    // #2: determine our next step
    if (isset($matches[2]))
    {
        if ($matches[2] == '>')
        {
            $trail[] = &$cur_page;
            parse_page_orders($page_orders, $cur_page[end($p)], $trail);
        }
        elseif ($matches[2] == '<' && count($trail)>0)
        {
            parse_page_orders($page_orders, array_pop($trail), $trail);
        }
    }
    else
    {
        // we're done. this should be our result.
        print_r($cur_page); 
    }
}
$pages = array();
$trail = array();
$page_orders = ',1,2,3>,4>,5,6,7<<,8';
parse_page_orders($page_orders, $pages, $trail);
print_r($pages);

?>

3 个答案:

答案 0 :(得分:1)

如果您对如何以“您的”格式解析字符串感兴趣:

    class Parser {

        function run($str) {
            preg_match_all('~(\d+)|[<>]~', $str, $a);
            $this->a = $a[0];
            return $this->expr();
        }

        function expr() {
            $q = array();
            while(1) {
                if(!count($this->a)) return $q;
                $sym = array_shift($this->a);
                if($sym == '<') return $q;
                if($sym == '>')
                    $q[count($q) - 1]['children'] = $this->expr();
                else
                    $q[] = array('id' => $sym);
            }
        }
    }


    $a = "1,2,3>4,>5,6,7<<,8>9,10,>11<,12,<,13,14";
    $p = new Parser;
    $result = $p->run($a);
    print_r($result);

答案 1 :(得分:0)

如果要将数据结构从javascript发送到php,请尝试使用JSON。它在javascript中看起来像这样:

var obj = {1:[], 
           2:[], 
           3:{
              4:{
                 5:[], 
                 6:[], 
                 7:[]
                }
             }, 
           8:[]};

var json = JSON.stringify(obj);

//Now send it to the server as a string

这就是你在服务器上所需要的,假设$ json现在已经获得了你在javascript中创建的字符串

<?php    
$arr = json_decode($strng, true);
print_r($arr);
?>

答案 2 :(得分:0)

当您想要返回更高级别(遇到&lt;符号)时,您的递归函数必须返回。相反,你的功能更深入。

逻辑应该是这样的:

//parse page order string or its single level
function parse_page_orders(&$page_orders)
{  
  $result=array();
  while($page_orders)
  {
    $token=nextToken($page_orders);
    if ($token=='>') //iterate deeper on >
    {
       $result[]=parse_page_orders($page_orders);
       continue;
    }
    if ($token=='<') 
       return $result;
    if (is_numeric($token))
       $result[]=parseInt($token);
  }
return $result;
}

function nextToken(&$page_orders)
{
  if(preg_match('/(\d+)/'),$page_orders,$m)
  {
     $page_orders=substr($page_orders,strlen($m[1]));
     return parseInt($m[1]);
  }
  else
  {
    $result=$page_orders{0};
    $page_orders=substr($page_orders,1);
    return $result;
  }
}