A completely fair and balanced comparison of php json libraries

gggeek.altervista.org 2006年12月11日 13:49 查看6132次 作者:   【
文章分类:PHP5研究[新]

Disclaimer: I'm biased

The recent release of php 5.2.0, which includes by default an extension for converting php values from and to the JSON format, is a good occasion for comparing the different existing php libraries which aim to provide the same capabilities.

The JSON homepage lists quite a few php libraries, but only 4 are in fact available for download and look stable and maintained:

The first one is the only library written in C. Its evident advantage in terms of execution speed is (was) accompanied by portability problems that the other three, being written purely in php, do not have.

The second one was (to the best of my knowledge) the first implementation of JSON in PHP. Its inclusion in PEAR is a guarantee of stability and quality of code.

The third one is more recent, but it is backed up by the company behind the PHP engine, and is part of a framework of components that is very fashionable at the moment and will probably see widespread adoption in the future.

The fourth one was built to add support for the json-rpc protocol to an existing xmlrpc implementation, and later expanded to better handle plain json. The json parsing code was originally taken from the Pear lib and incrementally improved.

The comparison revolves around 4 sections: features matrix, code examples, execution speed and encoding/decoding test results.

All comparisons have been carried out on the most recent code available as of the beginning of November 2006 (read: CVS or unstable versions used where available)

Feature matrix

This list is quite subjective both on the choice of features looked for and in the evaluation of their implementation. I will gladly accept any correction.

Feature PHP Json Pear Json Zend json XmlRpc json
Version 1.2.1 2006/03/31 1.31 2006/06/28 20061105-1470 CVS Id 1.25 2006/11/05
PHP version compatibility 4 (for windows the dll for php 4.3 and above is availabale on pecl4win), 5 4.0.6, 5 5 4.2, 5
PHP files used 0 1 6 2
Encodes to 7-bit ASCII clean JSON strings, using unicode escape sequences Yes Yes No Yes
Supports encoding php strings from different charsets Assumes UTF-8 Assumes UTF-8 Does not convert string data: it is up to the user to take care about conversion to the desired charset UTF-8, ISO-8859-1, ASCII
Supports decoding JSON data that has not an an array or object as top level element No Yes Yes Yes
Supports decoding JSON objects as either php arrays or objects Yes Yes Yes Yes
Supports distinguishing a failed decoding from decoding a single NULL value Yes (single NULL value cannot be decoded) No Yes (exception thrown) Yes
Supports decoding JSON to different charsets Only UTF-8

UTF-8, ISO-8859-1, ASCII
Supports features of Javascript outside the scope of JSON None: only data in accord with the Json spec is accepted Parses almost everything as valid (within an array) Some Tries to mimic the behaviour of common web browsers js engines;
keeps type information for float and integer php values (a float value of 1.0 will be encoded ad later decoded by the lib as float, even though in js only 'numbers' exists)
Extra features


Provides a compatibility layer that implement the same API as the PHP native json extension;
adds support for the json-rpc webservice dialect

Code samples

Goal PHP Json Pear Json Zend json XmlRpc json
Encode a php value to JSON string $out = json_encode($data); $value = new Services_JSON(); $out = $value->encode($data); $out = Zend_Json::encode($data); $value = php_jsonrpc_encode($data); $out = $value->serialize();
Decode a JSON string to PHP value (Json objects as php objects) $out = json_decode($data); $value = new Services_JSON(); $out = $value->decode($data); try { $out = Zend_Json::decode($data, Zend_Json::TYPE_OBJECT); } catch (Exception $e) { } $value = php_jsonrpc_decode_json($data); if ($value) $out = php_jsonrpc_decode($value, array('decode_php_objs'));
Decode a JSON string to PHP value (Json objects as php arrays) $out = json_decode($data, true); $value = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); $out = $value->decode($data); try { $out = Zend_Json::decode(); } catch (Exception $e) { } $value = php_jsonrpc_decode_json($data); if ($value) $out = php_jsonrpc_decode($value);

Speed comparison results

As with any benchmark results, take these with a grain of salt. No guarantee or claim of correctness is made.

A biggish php array was encoded then decoded 10 times in a row with each lib. Test results are in seconds, smaller is better.

The tests have been carried out on a Win XP machine, with PHP 5.1.6 and 5.2.0 running in CLI mode and a 'cleaned up' php.ini (and yes, I know most PHP applications are deployed on Linux, but that's what I had available at the moment. YMMV)

The XmlRpc lib appears twice because it can be used in two modes of operation: fully automated conversion or 'manual' conversion, where the user writes code to operate on the single jsonrpcval objects (see lib docs for more details).

PHP 5.1.6
Test PHP Json Pear Json Zend json XmlRpc json (a) XmlRpc json (m)
Data encoding 0.00798 0.23867 0.18198 0.68149 0.60186
Data decoding 0.01377 2.11908 0.69991 1.49128 1.41859
PHP 5.2.0
Test PHP Json Pear Json Zend json XmlRpc json (a) XmlRpc json (m)
Data encoding 0.00871 0.28658 0.46479 0.78107 0.73837
Data decoding 0.00947 2.23635 0.81878 1.70072 1.49629

An interesting result is PHP 5.2 seems to be slower on all libs, despite the claims made by the authors of it being much more optimized than its predecessors. Did I set it up wrong?

This is the data set used for testing, in PHP source format:

$data1 = array(1, 1.01, 'hello world', true, null, -1, 11.011, '~!@#$%^&*()_+|', false, null); $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1); $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2);

Encoding / decoding tests results

This last table is especially interesting, showing the different approach that the libraries have taken with regards to the JSON-vs-Javascript compatibility issue. In short: JSON is a subset of Javascript, and while every valid json string is valid Javascript, the reverse is not necessarily true. Every library I tested decodes correctly the json array defined as ["hello","world"], but not all of them accept as valid the string ['hello','world'], which is not valid Json but is valid javascript.

String decoding tests

  Value XmlRpc decoded JS dec. Native dec. Pear dec. Zend dec.
0 string(0) "" NULL
'Invalid data (empty string?)'
NULL NULL NULL NULL NULL
1 string(1) "1" int(1) number(1) NULL int(1) int(1)
2 string(4) "true" bool(true) bool(true) NULL bool(true) bool(true)
3 string(4) "null" NULL NULL NULL NULL NULL NULL
4 string(7) ""hello"" string(5) "hello" string(5) "hello" NULL string(5) "hello" string(5) "hello"
5 string(11) "not a value" NULL
'Invalid data'

NULL NULL NULL
'Illegal Token'
6 string(2) "[]" array(0) { } array(0) { } array(0) { } array(0) { } array(0) { }
7 string(3) "[1]" array(1) { [0]=> int(1) } array(1) { [0]=> number(1) } array(1) { [0]=> int(1) } array(1) { [0]=> int(1) } array(1) { [0]=> int(1) }
8 string(5) "[1.1]" array(1) { [0]=> float(1.1) } array(1) { [0]=> number(1.1) } array(1) { [0]=> float(1.1) } array(1) { [0]=> float(1.1) } array(1) { [0]=> float(1.1) }
9 string(7) "[-1E+4]" array(1) { [0]=> float(-10000) } array(1) { [0]=> number(-10000) } array(1) { [0]=> float(-10000) } array(1) { [0]=> float(-10000) } array(1) { [0]=> float(-10000) }
10 string(10) "[100.0e-2]" array(1) { [0]=> float(1) } array(1) { [0]=> number(1) } array(1) { [0]=> float(1) } array(1) { [0]=> float(1) } array(1) { [0]=> float(1) }
11 string(4) "[.5]" NULL
'Invalid data'
array(1) { [0]=> number(0.5) } NULL array(1) { [0]=> float(0.5) } array(1) { [0]=> float(0.5) }
12 string(4) "[5.]" array(1) { [0]=> float(5) } array(1) { [0]=> number(5) } array(1) { [0]=> float(5) } array(1) { [0]=> int(5) } array(1) { [0]=> int(5) }
13 string(3) "[.]" NULL
'Invalid data'

NULL array(1) { [0]=> NULL } NULL
'Illegal number format: .'
14 string(6) "[5..5]" NULL
'Invalid data'

NULL array(1) { [0]=> NULL } NULL
'Missing "," in array encoding: [5..5]'
15 string(5) "[10e]" NULL
'Invalid data'

NULL array(1) { [0]=> NULL } NULL
'Illegal Token'
16 string(5) "[e10]" NULL
'Invalid data'

NULL array(1) { [0]=> NULL } NULL
'Illegal Token'
17 string(7) "[010e2]" NULL
'Invalid data'

NULL array(1) { [0]=> float(1000) } array(1) { [0]=> float(1000) }
18 string(7) "[010.2]" NULL
'Invalid data'

NULL array(1) { [0]=> float(10.2) } array(1) { [0]=> float(10.2) }
19 string(5) "[010]" NULL
'Invalid data'
array(1) { [0]=> number(8) } NULL array(1) { [0]=> int(10) } array(1) { [0]=> int(10) }
20 string(6) "[0xFF]" array(1) { [0]=> int(255) } array(1) { [0]=> number(255) } NULL array(1) { [0]=> int(0) } NULL
'Illegal Token'
21 string(6) "[0xff]" array(1) { [0]=> int(255) } array(1) { [0]=> number(255) } NULL array(1) { [0]=> int(0) } NULL
'Illegal Token'
22 string(6) "[true]" array(1) { [0]=> bool(true) } array(1) { [0]=> bool(true) } array(1) { [0]=> bool(true) } array(1) { [0]=> bool(true) } array(1) { [0]=> bool(true) }
23 string(6) "[TRUE]" array(1) { [0]=> bool(true) }
NULL array(1) { [0]=> bool(true) } NULL
'Illegal Token'
24 string(6) "[null]" array(1) { [0]=> NULL } array(1) { [0]=> undefined } array(1) { [0]=> NULL } array(1) { [0]=> NULL } array(1) { [0]=> NULL }
25 string(6) "[NULL]" array(1) { [0]=> NULL }
NULL array(1) { [0]=> NULL } NULL
'Illegal Token'
26 string(4) "[""]" array(1) { [0]=> string(0) "" } array(1) { [0]=> string(0) "" } array(1) { [0]=> string(0) "" } array(1) { [0]=> string(0) "" } array(1) { [0]=> string(0) "" }
27 string(5) "["a"]" array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" }
28 string(9) " [ "a" ] " array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" }
29 string(4) "[1,]" array(2) { [0]=> int(1) [1]=> NULL } array(2) { [0]=> number(1) [1]=> undefined } NULL array(2) { [0]=> int(1) [1]=> NULL } array(1) { [0]=> int(1) }
30 string(3) "[,]" array(2) { [0]=> NULL [1]=> NULL } array(2) { [0]=> undefined [1]=> undefined } NULL array(2) { [0]=> NULL [1]=> NULL } array(1) { [0]=> NULL }
31 string(4) "[,1]" array(2) { [0]=> NULL [1]=> int(1) } array(2) { [0]=> undefined [1]=> number(1) } NULL array(2) { [0]=> NULL [1]=> int(1) } array(2) { [0]=> NULL [1]=> int(1) }
32 string(6) "[1,,1]" array(3) { [0]=> int(1) [1]=> NULL [2]=> int(1) } array(3) { [0]=> number(1) [1]=> undefined [2]=> number(1) } NULL array(3) { [0]=> int(1) [1]=> NULL [2]=> int(1) } array(3) { [0]=> int(1) [1]=> NULL [2]=> int(1) }
33 string(19) "// comment here [1]" NULL
'Invalid data'

NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
34 string(19) "[// comment here 1]" NULL
'Invalid data'

NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
35 string(19) "[1// comment here ]" NULL
'Invalid data'

NULL array(1) { [0]=> NULL } NULL
'Illegal Token'
36 string(19) "[1]// comment here " NULL
'Invalid data (array missing closing bracket?)'

NULL NULL NULL
'Illegal Token'
37 string(19) "/*comment here*/[1]" array(1) { [0]=> int(1) } array(1) { [0]=> number(1) } NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
38 string(19) "[/*comment here*/1]" array(1) { [0]=> int(1) } array(1) { [0]=> number(1) } NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
39 string(19) "[1/*comment here*/]" array(1) { [0]=> int(1) } array(1) { [0]=> number(1) } NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
40 string(19) "[1]/*comment here*/" array(1) { [0]=> int(1) } array(1) { [0]=> number(1) } NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
41 string(7) "/**/[1]" array(1) { [0]=> int(1) } array(1) { [0]=> number(1) } NULL NULL NULL
'Illegal Token'
42 string(6) "// [1]" NULL
'Invalid data'

NULL NULL NULL
'Illegal Token'
43 string(20) "[1 // comment here ]" NULL
'Invalid data'

NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
44 string(20) "[ // comment here 1]" NULL
'Invalid data'

NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
45 string(18) "[1]// comment here" NULL
'Invalid data (array missing closing bracket?)'
array(1) { [0]=> number(1) } NULL NULL NULL
'Illegal Token'
46 string(19) "[1] // comment here" NULL
'Invalid data (array missing closing bracket?)'

NULL array(1) { [0]=> int(1) } NULL
'Illegal Token'
47 string(28) "["a // this is a comment b"]" NULL
'Invalid data (line terminator char inside string?)'

NULL array(1) { [0]=> string(2) "ab" } array(1) { [0]=> string(24) "a // this is a comment b" }
48 string(32) "["a // this is not a comment b"]" array(1) { [0]=> string(28) "a // this is not a comment b" } array(1) { [0]=> string(28) "a // this is not a comment b" } array(1) { [0]=> string(28) "a // this is not a comment b" } array(1) { [0]=> string(28) "a // this is not a comment b" } array(1) { [0]=> string(28) "a // this is not a comment b" }
49 string(5) "['a']" array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } NULL array(1) { [0]=> string(1) "a" } NULL
'Illegal Token'
50 string(4) "["a]" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> NULL } array(1) { [0]=> string(2) "a]" }
51 string(4) "[a"]" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> NULL } NULL
'Illegal Token'
52 string(5) "['a"]" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> NULL } NULL
'Illegal Token'
53 string(5) "["a']" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> NULL } array(1) { [0]=> string(3) "a']" }
54 string(3) "[']" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> NULL } NULL
'Illegal Token'
55 string(4) "['']" array(1) { [0]=> string(0) "" } array(1) { [0]=> string(0) "" } NULL array(1) { [0]=> string(0) "" } NULL
'Illegal Token'
56 string(5) "[''']" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> NULL } NULL
'Illegal Token'
57 string(3) "["]" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> NULL } array(1) { [0]=> string(1) "]" }
58 string(5) "["""]" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> NULL } NULL
'Missing "," in array encoding: ["""]'
59 string(5) "["'"]" array(1) { [0]=> string(1) "'" } array(1) { [0]=> string(1) "'" } array(1) { [0]=> string(1) "'" } array(1) { [0]=> string(1) "'" } array(1) { [0]=> string(1) "'" }
60 string(5) "['"']" array(1) { [0]=> string(1) """ } array(1) { [0]=> string(1) """ } NULL array(1) { [0]=> string(1) """ } NULL
'Illegal Token'
61 string(6) "["'"]" array(1) { [0]=> string(1) "'" } array(1) { [0]=> string(1) "'" } NULL array(1) { [0]=> string(1) "'" } NULL
'Illegal escape sequence ''''
62 string(7) "["\'"]" array(1) { [0]=> string(2) "'" } array(1) { [0]=> string(2) "'" } array(1) { [0]=> string(2) "'" } array(1) { [0]=> string(2) "'" } array(1) { [0]=> string(2) "'" }
63 string(6) "["""]" array(1) { [0]=> string(1) """ } array(1) { [0]=> string(1) """ } array(1) { [0]=> string(1) """ } array(1) { [0]=> string(1) """ } array(1) { [0]=> string(1) """ }
64 string(5) "[""]" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> string(1) "" } array(1) { [0]=> string(2) ""]" }
65 string(6) "["\"]" array(1) { [0]=> string(1) "" } array(1) { [0]=> string(1) "" } array(1) { [0]=> string(1) "" } array(1) { [0]=> string(1) "" } array(1) { [0]=> string(1) "" }
66 string(7) "["\"]" NULL
'Invalid data (string missing closing quote?)'

NULL array(1) { [0]=> string(2) "\" } array(1) { [0]=> string(3) ""]" }
67 string(6) " ["a"]" array(1) { [0]=> string(1) "a" }
array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" }
68 string(6) "[ "a"]" array(1) { [0]=> string(1) "a" }
array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" }
69 string(6) "["a "]" NULL
'Invalid data (line terminator char inside string?)'

NULL array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(2) "a " }
70 string(6) "["a" ]" array(1) { [0]=> string(1) "a" }
array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" }
71 string(6) "["a"] " array(1) { [0]=> string(1) "a" }
array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" } array(1) { [0]=> string(1) "a" }
72 string(16) "["u0041u00DC"]" array(1) { [0]=> string(2) "AÜ" } array(1) { [0]=> string(2) "AÜ" } array(1) { [0]=> string(3) "AÃœ" } array(1) { [0]=> string(3) "AÃœ" } NULL
'Illegal escape sequence 'u''
73 string(16) "["btfvrn"]" array(1) { [0]=> string(6) " " } array(1) { [0]=> string(6) " v " } NULL array(1) { [0]=> string(7) " v " } NULL
'Illegal escape sequence 'v''
74 string(14) "["btfrn"]" array(1) { [0]=> string(5) " " } array(1) { [0]=> string(5) " " } array(1) { [0]=> string(5) " " } array(1) { [0]=> string(5) " " } array(1) { [0]=> string(5) " " }
75 string(12) "["x41xDC"]" array(1) { [0]=> string(2) "AÜ" } array(1) { [0]=> string(2) "AÜ" } NULL array(1) { [0]=> string(8) "x41xDC" } NULL
'Illegal escape sequence 'x''
76 string(7) "[ ] [ ]" NULL
'Invalid data (unmatched array closing bracket?)'

NULL array(1) { [0]=> NULL } array(0) { }
77 string(9) "["a" "b"]" NULL
'Invalid data (unescaped quote char inside string?)'

NULL array(1) { [0]=> string(5) "a" "b" } NULL
'Missing "," in array encoding: ["a" "b"]'
78 string(5) "[1 2]" NULL
'Invalid data'

NULL array(1) { [0]=> NULL } NULL
'Missing "," in array encoding: [1 2]'
79 string(4) "[{}]" array(1) { [0]=> array(0) { } } array(1) { [0]=> object(stdClass) (0) { } } array(1) { [0]=> object(stdClass)#5 (0) { } } array(1) { [0]=> array(0) { } } array(1) { [0]=> array(0) { } }
80 string(7) "[ { } ]" array(1) { [0]=> array(0) { } } array(1) { [0]=> object(stdClass) (0) { } } array(1) { [0]=> object(stdClass)#7 (0) { } } array(1) { [0]=> array(0) { } } array(1) { [0]=> array(0) { } }
81 string(5) "[{1}]" NULL
'Invalid data (missing object member name?)'

NULL array(1) { [0]=> array(0) { } } NULL
'Missing key in object encoding: [{1}]'
82 string(7) "[{1:1}]" array(1) { [0]=> array(1) { [1]=> int(1) } } array(1) { [0]=> object(stdClass) (1) { [1]=> number(1) } } NULL array(1) { [0]=> array(1) { [1]=> int(1) } } NULL
'Missing key in object encoding: [{1:1}]'
83 string(6) "[{:1}]" NULL
'Invalid data (missing object member name?)'

NULL array(1) { [0]=> array(0) { } } NULL
'Missing key in object encoding: [{:1}]'
84 string(8) "[{"1":}]" NULL
'Invalid data (empty string?)'

NULL array(1) { [0]=> array(0) { } } array(1) { [0]=> array(1) { [1]=> NULL } }
85 string(9) "[{"1":1}]" array(1) { [0]=> array(1) { [1]=> int(1) } } array(1) { [0]=> object(stdClass) (1) { [1]=> number(1) } } array(1) { [0]=> object(stdClass)#7 (1) { ["1"]=> int(1) } } array(1) { [0]=> array(1) { [1]=> int(1) } } array(1) { [0]=> ar
责任编辑:抽烟的蚊子

给文章打分...

平均分:0.8(26 次)

-5 -4 -3 -2 -1 0 1 2 3 4 5
1

顶一下

发表我的见解...

  • 您的大名: 留空为匿名
  • 您的主页:
  • 您的邮箱: