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_exportor serializeis what you're looking for. var_exportwill render a PHP parsable array syntax, and serializewill 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 replfunction.)
(删除从 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 serializefunction:
我认为您正在寻找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 unserializefunction.
它允许您以可读格式保存数组的内容,稍后您可以使用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));

