2012-06-06 2 views
0

Не уверен, что я делаю неправильно с этой функцией рекурсии. У меня есть массив с деревом веб-сайта, и страница, которую я ищу, может быть бесконечно глубокой. Функция проходит через все возможности, но иногда не останавливается, когда находит правильную «страницу».PHP Рекурсия не останавливается

Массив

$haystack = array(
    array("id" => 1,"parent" => 0,"route" => "home","children" => array()), 
    array("id" => 2,"parent" => 0,"route" => "news","children" => array()), 
    array("id" => 3,"parent" => 0,"route" => "photography","children" => array(
       array("id" => 6,"parent" => 3,"route" => "photography/portraits","children" => array()), 
       array("id" => 7,"parent" => 3,"route" => "photography/countries","children" => array()), 
       array("id" => 8,"parent" => 3,"route" => "photography/landscapes","children" => array(
           array("id" => 9,"parent" => 8,"route" => "photography/landscapes/city","children" => array()), 
           array("id" => 10,"parent" => 8,"route" => "photography/landscapes/wilderness","children" => array()) 
          ) 
       ) 
     ) 
    ), 
    array("id" => 4,"parent" => 0,"route" => "about","children" => array()), 
    array("id" => 5,"parent" => 0,"route" => "contact","children" => array()), 
); 

рекурсии функция

function recurse($needle = -1, $haystack = NULL){ 
    $_tmp = array(); 

    foreach($haystack as $key => $item) 
    { 
     echo $needle ." === ". $item["id"] . "<br/>"; 

     if((string)$item["id"] === (string)$needle){ 
      echo "Found: " . $needle . "<br/><br/>"; 
      $_tmp = $item; 
      break; 
      //return $item; <-- this doesn't work either 
     } else { 
      $_tmp = recurse($needle, $item["children"]); 
     } 
    } 
    return $_tmp; 
} 

Тестовые:

$test = recurse(3); 
print_r($test); 

$test = recurse(7); 
print_r($test); 

$test = recurse(9); 
print_r($test); 

Последние тестовые выходы:

9 === 1 
9 === 2 
9 === 4 
9 === 7 
9 === 8 
9 === 11 
9 === 12 
9 === 13 
9 === 14 
9 === 15 
9 === 3 
9 === 9 
Found: 9 <-- should stop here, but continues 

9 === 5 
9 === 6 
Array 
(
) 
+1

Вы пробовали 'вернуть $ пункт;' * без * 'сломать;'? – Hassan

+3

Название вопроса не должно быть смешным, но я постоянно его читаю и смеюсь. – rdlowrey

+0

Проверьте это. http://stackoverflow.com/a/10777501/1420642 Это для вложенных комментариев, но это почти то же самое –

ответ

1

Вот немного модифицированная функция рекурсию, которая исправляет эту проблему у вас есть:

function recurse($needle = -1, $haystack = NULL){ 
    static $_tmp = array(); 

    if (count($_tmp) == 0 && $haystack != NULL && count($haystack) > 0) { 
     foreach($haystack as $key => $item) { 
      if (count($_tmp) == 0) { 
       echo $needle ." === ". $item["id"] . "<br/>\n"; 

       if((string)$item["id"] === (string)$needle){ 
        echo "Found: " . $needle . "<br/>\n"; 
        $_tmp = $item; 
        break; 
       } elseif (!empty($item["children"])) { 
        echo "calling ". $item["id"]. ".children <br/>\n"; 
        $_tmp = recurse($needle, $item["children"]); 
       } 
      } 
     } 
    } 
    return $_tmp; 
} 

в основном это объявляет статическую переменную $_tmp, которая инициализируется только один раз и, а затем чек обрабатывать петлю, только если $_tmpпуст удостоверяется, чтобы остановить мех была обработана один раз игла.

Online working demo of above code

+0

Я возвращаю значение, но есть ли способ остановить все процессы? Ваш тестовый результат показывает, что он продолжает рекурсию после того, как он нашел иглу. Если когда-либо у меня есть огромный массив, 1000 предметов или около того, нет смысла продолжать его, если я ищу что-то, скажем, в первом 10. Кроме того, если бы я мог остановить процесс в этот момент, я бы все равно возвращаемое значение. – pioSko

+0

Вы можете сделать его более эффективным, проверив размер статической переменной внутри цикла, как в моем последнем изменении. Смотрите демо здесь: g ideone.com/WXtNB – anubhava

+0

Спасибо, анубхава! За работой :) – pioSko

3

Он возвращается, но продолжается в другом рекурсивном кадре. Например, вызовы: 1 -> 2 -> 3 -> 4. Возврат из 4, но 3 (1 -> 2 -> 3) продолжает выполнение цикла.

+0

Да, я знаю, но я думал, что возвращение должно было остановить его. Я попробовал «перерыв 2», но я получаю сообщение об ошибке. Я не хочу, чтобы функция просто остановила все: P – pioSko

+0

Это не очень хорошая практика, но вы можете передать некоторую логическую переменную, первоначально установленную в false по ссылке, и установите ее перед истиной до истины. Перед началом проверки цикла это значение и возврат, если оно истинно. – Ruben

1

Вы могли бы пойти вниз массив, только если вы не можете найти что-либо на уровне вы, что-то вроде этого:

function recurse($needle = -1, $haystack = NULL){ 
    $_tmp = array(); 

    foreach($haystack as $key => $item) 
    { 
     echo $needle ." === ". $item["id"] . "<br/>"; 

     if((string)$item["id"] === (string)$needle){ 
      echo "Found: " . $needle . "<br/><br/>"; 
      $_tmp = $item; 
      break; 
      //return $item; <-- this doesn't work either 
     } 
    } 
    if (empty($_tmp)) 
     foreach($haystack as $key => $item) 
     { 
      $_tmp = recurse($needle, $item["children"]); 
     } 

    return $_tmp; 
} 
Смежные вопросы