Intereting Posts
PHP. Может ли автоматическая обработка каждой переменной $ _POST быть проблемой безопасности? Комбинируйте подготовленные PHP записи с LIKE Как проверить X-редактируемый запрос в laravel (на стороне сервера) Назначить значение jquery переменной php PHP: «Примечание: неопределенная переменная», «Примечание: неопределенный индекс» и «Примечание: неопределенное смещение» Yii – Поймать все входящие запросы логин с именем пользователя или адресом электронной почты в php Разбор HTML-страницы с использованием curl и xpath в PHP Функция set_select () не работает Я не могу запросить с помощью% в коллекции phalcon Как имитировать более одного запроса (то есть 4000 или более) на одной странице для проверки производительности? Пароль не проверяется с помощью функции password_verify Передача переменной PHP в функцию jQuery Свойство Doctrine ReflectionException не существует Я запутался с Memcache и Memcached vs php5-memcache

Проверка массивов для рекурсии

Каков наилучший способ проверить, является ли массив рекурсивным в PHP?

Учитывая следующий код:

<?php $myarray = array('test',123); $myarray[] = &$myarray; print_r($myarray); ?> 

Из руководства PHP:

Print_r () будет отображать RECURSION, когда он попадает в третий элемент массива.

Кажется, нет никакого другого способа сканирования массива для рекурсивных ссылок, поэтому, если вам нужно проверить их, вам придется использовать print_r () со своим вторым параметром для захвата вывода и поиска слова RECURSION ,

Есть ли более элегантный способ проверки?

PS. Вот как я проверяю и получаю рекурсивные ключи массива с помощью regex и print_r ()

 $pattern = '/\n \[(\w+)\] => Array\s+\*RECURSION\*/'; preg_match_all($pattern, print_r($value, TRUE), $matches); $recursiveKeys = array_unique($matches[1]); 

благодаря

Всегда интересно попробовать «невозможные» проблемы!

Вот функция, которая будет обнаруживать рекурсивные массивы, если рекурсия происходит на верхнем уровне:

 function is_recursive(array &$array) { static $uniqueObject; if (!$uniqueObject) { $uniqueObject = new stdClass; } foreach ($array as &$item) { if (!is_array($item)) { continue; } $item[] = $uniqueObject; $isRecursive = end($array) === $uniqueObject; array_pop($item); if ($isRecursive) { return true; } } return false; } 

Смотрите в действии .

Обнаружение рекурсии на любом уровне, очевидно, было бы более сложным, но я думаю, мы можем согласиться с тем, что это кажется выполнимым.

Обновить

И вот рекурсивное (каламбур не предназначенное, но приятное, тем не менее) решение, которое обнаруживает рекурсию на любом уровне:

 function is_recursive(array &$array, array &$alreadySeen = array()) { static $uniqueObject; if (!$uniqueObject) { $uniqueObject = new stdClass; } $alreadySeen[] = &$array; foreach ($array as &$item) { if (!is_array($item)) { continue; } $item[] = $uniqueObject; $recursionDetected = false; foreach ($alreadySeen as $candidate) { if (end($candidate) === $uniqueObject) { $recursionDetected = true; break; } } array_pop($item); if ($recursionDetected || is_recursive($item, $alreadySeen)) { return true; } } return false; } 

Смотрите в действии .

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

Я глубоко вникал в это подробно, и мне не удалось найти какой-либо полезный механизм для обнаружения рекурсии в массивах PHP.

Вопрос сводится к тому, можно ли сказать, являются ли две переменные PHP ссылками на одно и то же.

Если вы работаете с объектами, а не с массивами (или даже с объектами внутри ваших массивов), то это возможно, так как можно узнать, являются ли два объекта одной и той же ссылкой с помощью spl_object_hash() . Поэтому, если у вас есть объекты в вашей структуре, вы можете обнаружить рекурсию, пройдя по дереву и сравнивая объекты.

Однако для обычных переменных – то есть не-объектов – это невозможно легко обнаружить с помощью стандартного PHP.

Работа вокруг заключается в использовании print_r() (как вы уже знаете) или var_dump() , но ни один из них не является особенно элегантным решением.

Существует также функция, предоставляемая xDebug, которая может помочь, xdebug_debug_zval() , но это, очевидно, доступно только в том случае, если вы установили xDebug, что не рекомендуется в производственной системе.

Дополнительные советы и предложения доступны здесь .

Следующая функция проще [мнение], чем код в принятом ответе, и, похоже, работает на любой случай использования, который я смог усовершенствовать. Это также кажется удивительно быстрым, как правило, с микросекундами, хотя я не провел обширного бенчмаркинга. Если есть проблема с этим, я был бы признателен, если бы кто-нибудь мог указать на это?

 // returns TRUE iff the passed object or array contains // a self-referencing object or array function is_r($obj, &$visited=array()) { $visited[] = $obj; foreach ($obj as $el) { if (is_object($el) || is_array($el)) { if (in_array($el, $visited, TRUE)) return TRUE; if (is_r($el, $visited)) return TRUE; } } return FALSE; } 

Я полагаю, вы не можете это проверить. Прочтите Справочный документ для получения дополнительной информации по ссылке.

Вот функция для проверки RECURSION (из комментариев PHP doc), хотя это кажется очень медленным (я бы не предложил):

  function is_array_reference ($arr, $key) { $isRef = false; ob_start(); var_dump($arr); if (strpos(preg_replace("/[ \n\r]*/i", "", preg_replace("/( ){4,}.*(\n\r)*/i", "", ob_get_contents())), "[" . $key . "]=>&") !== false) $isRef = true; ob_end_clean(); return $isRef; }