Преобразование var_dump массива обратно в переменную массива

Я никогда не думал об этом до сегодняшнего дня, но после поиска в Интернете я действительно ничего не нашел. Возможно, я не формулировал это прямо в поиске.

Учитывая массив (из нескольких измерений или нет):

$data = array('this' => array('is' => 'the'), 'challenge' => array('for' => array('you'))); 

Когда var_dumped:

 array(2) { ["this"]=> array(1) { ["is"]=> string(3) "the" } ["challenge"]=> array(1) { ["for"]=> array(1) { [0]=> string(3) "you" } } } 

Проблема заключается в следующем: каков наилучший оптимизированный метод перекомпиляции массива в пригодный для использования массив для PHP? Как undump_var() . Независимо от того, все ли данные находятся в одной строке в качестве вывода в браузере или содержит ли строки разрывы в качестве вывода на терминал.

Это только вопрос регулярного выражения? Или есть другой способ? Я ищу творчество.

ОБНОВЛЕНИЕ: Примечание. Я знаком с сериализацией и несериализацией людей. Я не ищу альтернативных решений. Это вызов кода, чтобы понять, можно ли его сделать оптимизированным и творческим способом. Поэтому serialize и var_export здесь не являются решениями . И они не лучшие ответы.

var_export или serialize – это то, что вы ищете. var_export будет отображать синтаксис синтаксического var_export PHP, и serialize визуализацию, отличную от человека, но обратимую преобразование «array to string» …

Редактировать Хорошо, за вызов:

В принципе, я преобразовываю вывод в сериализованную строку (а затем неэтериализую ее). Я не утверждаю, что это идеально, но, похоже, он работает над некоторыми довольно сложными структурами, которые я пробовал …

 function unvar_dump($str) { if (strpos($str, "\n") === false) { //Add new lines: $regex = array( '#(\\[.*?\\]=>)#', '#(string\\(|int\\(|float\\(|array\\(|NULL|object\\(|})#', ); $str = preg_replace($regex, "\n\\1", $str); $str = trim($str); } $regex = array( '#^\\040*NULL\\040*$#m', '#^\\s*array\\((.*?)\\)\\s*{\\s*$#m', '#^\\s*string\\((.*?)\\)\\s*(.*?)$#m', '#^\\s*int\\((.*?)\\)\\s*$#m', '#^\\s*bool\\(true\\)\\s*$#m', '#^\\s*bool\\(false\\)\\s*$#m', '#^\\s*float\\((.*?)\\)\\s*$#m', '#^\\s*\[(\\d+)\\]\\s*=>\\s*$#m', '#\\s*?\\r?\\n\\s*#m', ); $replace = array( 'N', 'a:\\1:{', 's:\\1:\\2', 'i:\\1', 'b:1', 'b:0', 'd:\\1', 'i:\\1', ';' ); $serialized = preg_replace($regex, $replace, $str); $func = create_function( '$match', 'return "s:".strlen($match[1]).":\\"".$match[1]."\\"";' ); $serialized = preg_replace_callback( '#\\s*\\["(.*?)"\\]\\s*=>#', $func, $serialized ); $func = create_function( '$match', 'return "O:".strlen($match[1]).":\\"".$match[1]."\\":".$match[2].":{";' ); $serialized = preg_replace_callback( '#object\\((.*?)\\).*?\\((\\d+)\\)\\s*{\\s*;#', $func, $serialized ); $serialized = preg_replace( array('#};#', '#{;#'), array('}', '{'), $serialized ); return unserialize($serialized); } 

Я тестировал его на сложной структуре, такой как:

 array(4) { ["foo"]=> string(8) "Foo"bar"" [0]=> int(4) [5]=> float(43.2) ["af"]=> array(3) { [0]=> string(3) "123" [1]=> object(stdClass)#2 (2) { ["bar"]=> string(4) "bart" ["foo"]=> array(1) { [0]=> string(2) "re" } } [2]=> NULL } } 

Нет другого способа, кроме ручного разбора в зависимости от типа. Я не добавлял поддержку объектов, но он очень похож на массивы; вам просто нужно сделать магию отражения, чтобы заполнить не только публичные свойства и не вызвать конструктор.

EDIT: Добавлена ​​поддержка объектов … Магия отражения …

 function unserializeDump($str, &$i = 0) { $strtok = substr($str, $i); switch ($type = strtok($strtok, "(")) { // get type, before first parenthesis case "bool": return strtok(")") === "true"?(bool) $i += 10:!$i += 11; case "int": $int = (int)substr($str, $i + 4); $i += strlen($int) + 5; return $int; case "string": $i += 11 + ($len = (int)substr($str, $i + 7)) + strlen($len); return substr($str, $i - $len - 1, $len); case "float": return (float)($float = strtok(")")) + !$i += strlen($float) + 7; case "NULL": return NULL; case "array": $array = array(); $len = (int)substr($str, $i + 6); $i = strpos($str, "\n", $i) - 1; for ($entries = 0; $entries < $len; $entries++) { $i = strpos($str, "\n", $i); $indent = -1 - (int)$i + $i = strpos($str, "[", $i); // get key int/string if ($str[$i + 1] == '"') { // use longest possible sequence to avoid key and dump structure collisions $key = substr($str, $i + 2, - 2 - $i + $i = strpos($str, "\"]=>\n ", $i)); } else { $key = (int)substr($str, $i + 1); $i += strlen($key); } $i += $indent + 5; // jump line $array[$key] = unserializeDump($str, $i); } $i = strpos($str, "}", $i) + 1; return $array; case "object": $reflection = new ReflectionClass(strtok(")")); $object = $reflection->newInstanceWithoutConstructor(); $len = !strtok("(") + strtok(")"); $i = strpos($str, "\n", $i) - 1; for ($entries = 0; $entries < $len; $entries++) { $i = strpos($str, "\n", $i); $indent = -1 - (int)$i + $i = strpos($str, "[", $i); // use longest possible sequence to avoid key and dump structure collisions $key = substr($str, $i + 2, - 2 - $i + $i = min(strpos($str, "\"]=>\n ", $i)?:INF, strpos($str, "\":protected]=>\n ", $i)?:INF, $priv = strpos($str, "\":\"", $i)?:INF)); if ($priv == $i) { $ref = new ReflectionClass(substr($str, $i + 3, - 3 - $i + $i = strpos($str, "\":private]=>\n ", $i))); $i += $indent + 13; // jump line } else { $i += $indent + ($str[$i+1] == ":"?15:5); // jump line $ref = $reflection; } $prop = $ref->getProperty($key); $prop->setAccessible(true); $prop->setValue($object, unserializeDump($str, $i)); } $i = strpos($str, "}", $i) + 1; return $object; } throw new Exception("Type not recognized...: $type"); } 

(Здесь много «магических» чисел при увеличении счетчика строк строки $i , в основном просто длины строк ключевых слов и некоторых круглых скобок и т. Д.)

Если вы хотите кодировать / декодировать такой массив, вы должны либо использовать var_export() , который генерирует вывод в массиве PHP, например:

 array( 1 => 'foo', 2 => 'bar' ) 

может быть результатом этого. Вам придется использовать eval() чтобы вернуть массив обратно, и это потенциально опасный путь (особенно, поскольку eval() действительно выполняет PHP-код, поэтому простая вставка кода может заставить хакеров получить контроль над вашим скриптом PHP ).

Некоторые из лучших решений – serialize() , которые создают сериализованную версию любого массива или объекта; и json_encode() , который кодирует любой массив или объект с помощью формата JSON (что более предпочтительно для обмена данными между разными языками).

Трюк состоит в том, чтобы сопоставлять куски кода и "strings" , а по строкам ничего не делать, кроме как в противном случае – заменять:

 $out = preg_replace_callback('/"[^"]*"|[^"]+/','repl',$in); function repl($m) { return $m[0][0]=='"'? str_replace('"',"'",$m[0]) : str_replace("(,","(", preg_replace("/(int\((\d+)\)|\s*|(string|)\(\d+\))/","\\2", strtr($m[0],"{}[]","(), ") ) ); } 

выходы:

 array('this'=>array('is'=>'the'),'challenge'=>array('for'=>array(0=>'you'))) 

(удаление возрастающих числовых клавиш, начинающихся с 0, требует немного дополнительного учета, что может быть сделано в функции repl .)

пс. это не решает проблему строк, содержащих " , но, как кажется, var_dump не избегает содержимого строки, нет надежного решения этой проблемы (вы можете сопоставить \["[^"]*"\] но строка также может содержать "] )

Используйте regexp для изменения массива (.) {(. *)} Для массива ($ 1) и eval кода, это не так просто, как написано, потому что вам приходится иметь дело с соответствующими скобками и т. Д., Просто подсказка о том, как найти решение 😉

  • это будет полезно, если вы не можете изменить var_dump на var_export или сериализовать

Я думаю, что вы ищете функцию serialize :

serialize – создает сохраняемое представление значения

Он позволяет сохранять содержимое массива в читаемом формате, а позже вы можете прочитать массив с функцией unserialize .

Используя эти функции, вы можете хранить / извлекать массивы даже в текстовых / плоских файлах, а также в базе данных.