【问题标题】:PHP recursive function + array by reference = headachePHP递归函数+引用数组=头痛
【发布时间】:2010-12-14 15:14:00
【问题描述】:

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

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

翻译:忘记烦人的前导逗号。第 1、2、3 和 8 页是顶级页面 id,4 是 3 的子页面(“>”表示更深一层),5、6、7 是 4 的子页面。

一种更易读的格式如下所示:

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

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

问题是在整个递归函数中一切都很好,但是我在调​​用函数中丢失了第 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::references...

代码:

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

?>

【问题讨论】:

    标签: php recursion scope pass-by-reference


    【解决方案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);
    

    【讨论】:

      【解决方案2】:

      如果您想将数据结构从 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);
      ?>
      

      【讨论】:

      • 这是我的第一个倾向,但我似乎无法生成经过验证的 JSON 对象。可以在 JSON 对象中使用数字作为索引吗?
      • 是的,你可以。 PHP 要求密钥包含在“”中,因此您可以手动执行此操作,或者检查 stringify 函数是否为您执行此操作。从这里使用 JSON 对象:json.org/js.html
      • 另外一件事,你可能需要检查你在 PHP 中没有打开 magic_quotes,当你将它作为 GET 或 POST 参数发送到 PHP 时,它会混淆 json 字符串。
      【解决方案3】:

      当你想返回更高级别时(遇到

      逻辑应该是这样的:

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

      【讨论】:

      • 我不确定您所说的“它更深入”是什么意思。我通过 $trail 变量存储了一个反向引用。那应该把它带回来吧?
      猜你喜欢
      • 1970-01-01
      • 2020-10-02
      • 2015-04-27
      • 2021-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-06
      • 2014-06-09
      相关资源
      最近更新 更多