PHP рекурсивная функция + массив по ссылке = головная боль - PullRequest
1 голос
/ 09 ноября 2009

У меня интересная проблема. Основой проблемы является то, что моя последняя итерация ссылки на массив не кажется, "придерживаться", если хотите. Небольшой контекст: я разработал очень простую структуру данных для иерархии страниц, которая выглядит так:

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

Перевод: забудьте о надоедливых начальных запятых. Страницы 1, 2, 3 и 8 - это идентификаторы страниц верхнего уровня, 4 - это подстраница из 3 («>» означает углубление уровня), а 5, 6 и 7 - это подстраницы из 4.

Более читабельный формат будет выглядеть так:

1
2 * * +1010 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
                    (
                    )

            )

    )

)

Есть мысли?

[РЕДАКТИРОВАТЬ]: Я удалил пару остаточных я :: ссылки ...

КОД:

<?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 ]

1 голос
/ 09 ноября 2009

на случай, если вам интересно, как проанализировать строку в «вашем» формате:

    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 голосов
/ 09 ноября 2009

Когда вы хотите вернуться на более высокий уровень (встретите символ <), ваша рекурсивная функция должна вернуться. Вместо этого ваша функция идет глубже. </p>

Логика должна выглядеть примерно так:

//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 голосов
/ 09 ноября 2009

Если вы хотите отправить структуру данных из 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);
?>
...