2009-11-09 43 views
1

我有一个有趣的问题。这个问题的基础是,如果你愿意的话,我最后一次数组引用并不是 似乎“坚持”。一点背景知识:我设计了一个非常简单的数据结构,层次结构页是 看起来是这样的:PHP递归函数+数组引用=头痛

,1,2,3> 4>,5,6,7 < <,8

翻译:忘记恼人的领先逗号。页面1,2,3,& 8是顶级页面ID,4是子页面3('>'意思是移动更深的级别),5,6,& 7是4的子页面。

更人类可读的格式是这样的:

- 4
- - 5
- - 6
- - 7

不要问我为什么这样做。我还没有想出一个简单的方式来生成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 
        (
        ) 

      ) 

    ) 

) 

有什么想法?

[编辑]:我删除了几个残留的自我::引用...

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); 

?> 

回答

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); 
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); 
?> 
+0

那是我的第一个倾向,但我不能看起来似乎没有生成一个经过验证的JSON对象。你可以在JSON对象中使用数字作为索引吗? – landons 2009-11-09 13:47:46

+0

是的,你可以。 PHP要求将密钥包装在“”中,所以你可以手动执行,或者检查stringify函数是否为你做。使用这里的JSON对象:http://www.json.org/js.html – Marius 2009-11-09 13:58:51

+0

另一件事,你可能需要检查你没有在PHP中使用magic_quotes,当你发送时会与json字符串混淆它将PHP作为GET或POST参数。 – Marius 2009-11-09 14:00:14

0

当你想返回更高级别(遇到<符号),则必须返回递归函数。相反,你的功能更深入。

逻辑应该是这样的:

//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; 
    } 
} 
+0

我不确定你的意思是“更深入”。我通过$ trail变量存储了一个后退引用。这应该把它带回来吗? – landons 2009-11-09 14:57:13