php 将数组的 var_dump 转换回数组变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3531857/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert var_dump of array back to array variable
提问by Chuck Burgess
I have never really thought about this until today, but after searching the web I didn't really find anything. Maybe I wasn't wording it right in the search.
直到今天我才真正考虑过这个问题,但是在网上搜索之后我并没有真正找到任何东西。也许我在搜索中措辞不正确。
Given an array (of multiple dimensions or not):
给定一个数组(多维或非多维):
$data = array('this' => array('is' => 'the'), 'challenge' => array('for' => array('you')));
When var_dumped:
当 var_dumped 时:
array(2) { ["this"]=> array(1) { ["is"]=> string(3) "the" } ["challenge"]=> array(1) { ["for"]=> array(1) { [0]=> string(3) "you" } } }
The challenge is this: What is the best optimized method for recompiling the array to a useable array for PHP? Like an undump_var()
function. Whether the data is all on one line as output in a browser or whether it contains the line breaks as output to terminal.
挑战在于:将数组重新编译为可用于 PHP 的数组的最佳优化方法是什么?就像一个undump_var()
函数。数据是否全部在一行上作为浏览器中的输出,或者是否包含换行符作为输出到终端。
Is it just a matter of regex? Or is there some other way? I am looking for creativity.
这只是正则表达式的问题吗?或者有其他方法吗?我在寻找创造力。
UPDATE: Note. I am familiar with serialize and unserialize folks. I am not looking for alternative solutions. This is a code challenge to see if it can be done in an optimized and creative way. So serialize and var_export are not solutionshere. Nor are they the best answers.
更新:注意。我熟悉序列化和反序列化的人。我不是在寻找替代解决方案。这是一个代码挑战,看看它是否可以以优化和创造性的方式完成。所以serialize 和 var_export 不是这里的解决方案。它们也不是最好的答案。
回答by ircmaxell
var_export
or serialize
is what you're looking for. var_export
will render a PHP parsable array syntax, and serialize
will render a non-human readable but reversible "array to string" conversion...
var_export
或者serialize
是你正在寻找的。 var_export
将呈现 PHP 可解析的数组语法,serialize
并将呈现非人类可读但可逆的“数组到字符串”转换...
EditAlright, for the challenge:
编辑好吧,对于挑战:
Basically, I convert the output into a serialized string (and then unserialize it). I don't claim this to be perfect, but it appears to work on some pretty complex structures that I've tried...
基本上,我将输出转换为序列化字符串(然后将其反序列化)。我不认为这是完美的,但它似乎适用于我尝试过的一些非常复杂的结构......
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);
}
I tested it on a complex structure such as:
我在复杂的结构上对其进行了测试,例如:
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
}
}
回答by bwoebi
There's no other way than manual parsing depending on the type. I didn't add support for objects, but it's very similar to the arrays one; you just need to do some reflection magic to populate not only public properties and to not trigger the constructor.
除了根据类型手动解析外,别无他法。我没有添加对对象的支持,但它与数组非常相似;你只需要做一些反射魔法来填充公共属性并且不触发构造函数。
EDIT: Added support for objects... Reflection magic...
编辑:添加了对对象的支持......反射魔法......
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");
}
(Here are a lot of "magic" numbers when incrementing string position counter $i
, mostly just string lengths of the keywords and some parenthesis etc.)
(在增加字符串位置 counter 时$i
,这里有很多“神奇”数字,主要是关键字的字符串长度和一些括号等)
回答by Frxstrem
If you want to encode/decode an array like this, you should either use var_export()
, which generates output in PHP's array for, for instance:
如果你想对这样的数组进行编码/解码,你应该使用var_export()
,它会在 PHP 的数组中生成输出,例如:
array(
1 => 'foo',
2 => 'bar'
)
could be the result of it. You would have to use eval()
to get the array back, though, and that is a potentially dangerous way (especially since eval()
really executes PHP code, so a simple code injection could make hackers able to gain control over your PHP script).
可能是它的结果。但是,您必须使用eval()
来取回数组,这是一种潜在的危险方式(特别是因为eval()
真正执行 PHP 代码,因此简单的代码注入可能使黑客能够控制您的 PHP 脚本)。
Some even better solutions are serialize()
, which creates a serialized version of any array or object; and json_encode()
, which encodes any array or object with the JSONformat (which is more preferred for data exchange between different languages).
一些更好的解决方案是serialize()
,它创建任何数组或对象的序列化版本;和json_encode()
,它使用JSON格式对任何数组或对象进行编码(更适合不同语言之间的数据交换)。
回答by mvds
The trick is to match by chunks of code and "strings"
, and on strings do nothing but otherwise do the replacements:
诀窍是通过代码块和 进行匹配"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],"{}[]","(), ")
)
);
}
outputs:
输出:
array('this'=>array('is'=>'the'),'challenge'=>array('for'=>array(0=>'you')))
(removing ascending numeric keys starting at 0 takes a little extra accounting, which can be done in the repl
function.)
(删除从 0 开始的升序数字键需要一些额外的计算,这可以在repl
函数中完成。)
ps.this doesn't solve the problem of strings containing "
, but as it seems that var_dump doesn't escape string contents, there is no way to solve that reliably. (you could match \["[^"]*"\]
but a string may contain "]
as well)
附:这并不能解决包含 的字符串的问题"
,但似乎 var_dump 不会转义字符串内容,因此无法可靠地解决该问题。(您可以匹配,\["[^"]*"\]
但字符串也可能包含"]
)
回答by canni
Use regexp to change array(.) { (.*) } to array($1) and eval the code, this is not so easy as written because You have to deal with matching brackets etc., just a clue on how to find solution ;)
使用正则表达式将 array(.) { (.*) } 更改为 array($1) 并评估代码,这不像写的那么容易,因为您必须处理匹配的括号等,只是如何找到解决方案的线索;)
- this will be helpful if You cant change var_dump to var_export, or serialize
- 如果您无法将 var_dump 更改为 var_export 或序列化,这将很有帮助
回答by Sarfraz
I think you are looking for the serialize
function:
我认为您正在寻找serialize
功能:
serialize — Generates a storable representation of a value
serialize — 生成值的可存储表示
It allows you to save the contents of array in readable format and later you can read the array back with unserialize
function.
它允许您以可读格式保存数组的内容,稍后您可以使用unserialize
函数读回数组。
Using these functions, you can store/retrieve the arrays even in text/flat files as well as database.
使用这些函数,您甚至可以在文本/平面文件和数据库中存储/检索数组。
回答by Aurimas Rek?tys
Updated to NOT USE create_function, as it is DEPRECATED as of PHP 7.2.0. Instead it is replaced to use anonymous functions:
更新为 NOT USE create_function,因为它自 PHP 7.2.0 起已弃用。相反,它被替换为使用匿名函数:
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", $str);
$str = trim($str);
}
$regex = array(
'#^0*NULL0*$#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::{',
's::',
'i:',
'b:1',
'b:0',
'd:',
'i:',
';'
);
$serialized = preg_replace($regex, $replace, $str);
$func = function($match) {
return 's:'.strlen($match[1]).':"'.$match[1].'"';
};
$serialized = preg_replace_callback(
'#\s*\["(.*?)"\]\s*=>#',
$func,
$serialized
);
$func = 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);
}
$test = 'array(10) {
["status"]=>
string(1) "1"
["transactionID"]=>
string(14) "1532xxx"
["orderID"]=>
string(10) "1532xxx"
["value"]=>
string(8) "0.73xxx"
["address"]=>
string(1) "-"
["confirmations"]=>
string(3) "999"
["transaction_hash"]=>
string(64) "internxxx"
["notes"]=>
string(0) ""
["txCost"]=>
string(1) "0"
["txTimestamp"]=>
string(10) "1532078165"
}';
var_export(unvar_dump($test));