Преобразование 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 не являются решениями. И они не являются наилучшими ответами.
Ответы
Ответ 1
var_export
или serialize
- это то, что ты ищешь. var_export
будет отображать синтаксис синтаксического анализа синтаксического анализа PHP, а serialize
отобразит не-человеческий читаемый, но обратимый преобразование "массив в строку"...
Изменить Хорошо, за вызов:
В принципе, я конвертирую вывод в сериализованную строку (а затем неэтериализую ее). Я не утверждаю, что это идеально, но, похоже, работает над некоторыми довольно сложными структурами, которые я пробовал...
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
}
}
Ответ 2
Нет другого способа, кроме ручного разбора в зависимости от типа.
Я не добавлял поддержку объектов, но очень похож на массивы; вам просто нужно сделать магию отражения, чтобы заполнить не только общедоступные свойства и не запускать конструктор.
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
, в основном просто длина строк ключевых слов и некоторых скобок и т.д.)
Ответ 3
Если вы хотите кодировать/декодировать такой массив, вы должны либо использовать var_export()
, который генерирует вывод в массиве PHP, например:
array(
1 => 'foo',
2 => 'bar'
)
может быть результатом этого. Однако вам нужно будет использовать eval()
, чтобы вернуть массив, и это потенциально опасный путь (тем более что eval()
действительно выполняет PHP-код, поэтому простая вставка кода может заставить хакеров получить контроль над вашим PHP скрипт).
Некоторые даже лучшие решения: serialize()
, который создает сериализованную версию любого массива или объекта; и json_encode()
, который кодирует любой массив или объект с помощью JSON (что более предпочтительно для обмена данными между разными языками).
Ответ 4
Трюк должен совпадать с фрагментами кода и "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
.)
ps., это не решает проблему строк, содержащих "
, но, как кажется, var_dump не избегает содержимого строки, нет надежного решения. (вы можете соответствовать \["[^"]*"\]
, но строка может содержать "]
)
Ответ 5
Используйте regexp для изменения массива (.) {(. *)} до массива ($ 1) и eval кода, это не так просто, как написано, потому что вам нужно иметь дело с соответствующими скобками и т.д., просто подскажите, как найти решение;)
- это будет полезно, если вы не можете изменить var_dump в var_export или сериализовать
Ответ 6
Я думаю, что вы ищете функцию serialize
:
serialize - создает сохраняемый представление значения
Он позволяет сохранять содержимое массива в читаемом формате, а затем вы можете прочитать массив с помощью unserialize
.
Используя эти функции, вы можете хранить/извлекать массивы даже в текстовых/плоских файлах, а также в базе данных.