jsonevaltrickinphp

php从5.2版本开始提供json_encode()和json_decode()函数,分别用于json的序例化和反序列化。不幸的是,现在仍然有许多主机运行着php5.2之前的版本,所以就不得不自己动手写json解析了。

json encode

json的编码并没有什么难度,要点就两个:

对object、array中的元素进行递归遍历,注意要将关联数组转换成json中的object literal。
对字符串内容中引号、换行符等特殊字符进行转义,并将非ascii字符转换成unicode转义序列的形式。

下面是json编码方法的实现:

/**
* json encode
* @warn any input string must be utf-8 encoding
* @param {any} $data any type object to serialize.
* @return {string} serialized json string.
*/
function json_stringify($data) {
if (is_null($data)) return ‘null’;
if (is_scalar($data)) return json_stringify_scalar($data);
if (empty($data)) return ‘[]’;
if (is_object($data)) {
$data=get_object_vars($data);
if (empty($data)) return ‘{}’;
}
$keys=array_keys($data);
if ($keys===array_keys($keys)) {
$data=array_map(__function__,$data);
return ‘[‘.join(‘,’,$data).’]’;
} else {//不是有序数字下标的数组即视为关联数组
$a=array();
foreach ($data as $k=>$v) {
$a[]=json_stringify_scalar(strval($k)).’:’.json_stringify($v);
}
return ‘{‘.join(‘,’,$a).’}’;
}
}
function json_stringify_scalar($v) {
if (is_bool($v)) {
$v = $v?’true’:’false’;
} else if (is_string($v)) {
$v=addcslashes($v,”\t\n\r\”\/\\”);//转义特殊字符
//将所有非ascii字符转换成unicode escape格式
$v='”‘.preg_replace_callback(‘|[^\x00-\x7f]+|’,’_unicode_escape’,$v).'”‘;
}
return (string)$v;
}
function _unicode_escape($s) {
//warning:字符串必须为utf-8编码
$s=str_split(iconv(‘utf-8′,’ucs-2be’,$s[0]),2);
foreach ($s as $i=>$c) {
$s[$i]=sprintf(‘\u%02x%02x’,ord($c{0}),ord($c{1}));
}
return join(”,$s);
}

json decode

而将json转换成php中的对象就没有那么简单了,自己写parser进行词法分析、语法分析是很累人的。反观在javascript中实现json parse就简单多了,因为json本身即是javascript语言的子集,直接使用eval方法,就能将json字符串转换成js中的对象。

其实,看到javascript中的eval方法,实在不能不联想到php也有一个eval,它们的功能是类似的,都是将字符串当作代码运行。不同的是,js中的eval执行js代码,php的eval执行php代码。trick就在这里:要让php能直接用eval方法解析json,只要将json代码转换成php格式的代码就行了!如对于下面的json:

{
“name”:”cj”,
“age”:18,
“tags”:[“php”,”javascript”,”python”,”haskell”],
“life”:{
“summary”:”too complex!”
}
}

只要将其转换成这样的php代码就能直接eval了:

(object)array(
“name”=>”cj”,
“age”=>18,
“tags”=>array(“php”,”javascript”,”python”,”haskell”),
“life”=>(object)array(
“summary”=>”too complex!”
)
)

而将json转换成php代码则只需很少的步骤与注意点:

最终的实现代码出人意料的简单:

/**
* json decode
* @param {string} $s the string json data.
* @param {boolean} [$assoc=false] return assoc array if $assoc is true.
* @return decode result corresponding object.
*/
function json_parse($s,$assoc=false) {
static $strings,$count=0;
if (is_string($s)) {
$s=trim($s);
$strings=array();
//匹配字符串结束引号应该确保前面只能有偶数个’\’
//如 “ab\”c”中 \” 不能被视为字符串结束引号
$s=preg_replace_callback(‘/”([\s\s]*?(?

Posted in 未分类