我需要在平面文件中存储多维数据关联数组,以便进行缓存。我可能偶尔会遇到需要将其转换为JSON以在我的web应用程序中使用,但绝大多数情况下,我将直接在PHP中使用数组。

在这个文本文件中将数组存储为JSON还是PHP序列化数组更有效?我查看了一下,似乎在最新版本的PHP(5.3)中,json_decode实际上比反序列化更快。

我目前倾向于将数组存储为JSON,因为我觉得如果有必要的话,它更容易被人阅读,它可以在PHP和JavaScript中使用,而且从我所读到的,它甚至可能更快地解码(虽然不确定编码)。

有人知道有什么陷阱吗?有人有好的基准来显示这两种方法的性能优势吗?


当前回答

首先,我修改了脚本,做了更多的基准测试(也做了1000次而不是1次):

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL);

// Make a big, honkin test array
// You may need to adjust this depth to avoid memory limit errors
$testArray = fillArray(0, 5);

$totalJsonTime = 0;
$totalSerializeTime = 0;
$totalJsonWins = 0;

for ($i = 0; $i < 1000; $i++) {
    // Time json encoding
    $start = microtime(true);
    $json = json_encode($testArray);
    $jsonTime = microtime(true) - $start;
    $totalJsonTime += $jsonTime;

    // Time serialization
    $start = microtime(true);
    $serial = serialize($testArray);
    $serializeTime = microtime(true) - $start;
    $totalSerializeTime += $serializeTime;

    if ($jsonTime < $serializeTime) {
        $totalJsonWins++;
    }
}

$totalSerializeWins = 1000 - $totalJsonWins;

// Compare them
if ($totalJsonTime < $totalSerializeTime) {
    printf("json_encode() (wins: $totalJsonWins) was roughly %01.2f%% faster than serialize()\n", ($totalSerializeTime / $totalJsonTime - 1) * 100);
} else {
    printf("serialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than json_encode()\n", ($totalJsonTime / $totalSerializeTime - 1) * 100);
}

$totalJsonTime = 0;
$totalJson2Time = 0;
$totalSerializeTime = 0;
$totalJsonWins = 0;

for ($i = 0; $i < 1000; $i++) {
    // Time json decoding
    $start = microtime(true);
    $orig = json_decode($json, true);
    $jsonTime = microtime(true) - $start;
    $totalJsonTime += $jsonTime;

    $start = microtime(true);
    $origObj = json_decode($json);
    $jsonTime2 = microtime(true) - $start;
    $totalJson2Time += $jsonTime2;

    // Time serialization
    $start = microtime(true);
    $unserial = unserialize($serial);
    $serializeTime = microtime(true) - $start;
    $totalSerializeTime += $serializeTime;

    if ($jsonTime < $serializeTime) {
        $totalJsonWins++;
    }
}

$totalSerializeWins = 1000 - $totalJsonWins;


// Compare them
if ($totalJsonTime < $totalSerializeTime) {
    printf("json_decode() was roughly %01.2f%% faster than unserialize()\n", ($totalSerializeTime / $totalJsonTime - 1) * 100);
} else {
    printf("unserialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than json_decode()\n", ($totalJsonTime / $totalSerializeTime - 1) * 100);
}

// Compare them
if ($totalJson2Time < $totalSerializeTime) {
    printf("json_decode() was roughly %01.2f%% faster than unserialize()\n", ($totalSerializeTime / $totalJson2Time - 1) * 100);
} else {
    printf("unserialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than array json_decode()\n", ($totalJson2Time / $totalSerializeTime - 1) * 100);
}

function fillArray( $depth, $max ) {
    static $seed;
    if (is_null($seed)) {
        $seed = array('a', 2, 'c', 4, 'e', 6, 'g', 8, 'i', 10);
    }
    if ($depth < $max) {
        $node = array();
        foreach ($seed as $key) {
            $node[$key] = fillArray($depth + 1, $max);
        }
        return $node;
    }
    return 'empty';
}

我使用PHP 7的这个版本:

PHP 7.0.14 (cli)(已构建:2017年1月18日19:13:23)(NTS)版权所有(c) PHP Group Zend Engine v3.0.0,版权所有(c) 1998-2016 Zend技术 与Zend OPcache v7.0.14,版权(c) 1999-2016,由Zend Technologies

我的结果是:

Serialize()(胜:999)比json_encode()快大约10.98% Unserialize()(胜:987)大约比json_decode()快33.26% Unserialize()(胜:987)大约比array快48.35% json_decode ()

显然,序列化/反序列化是最快的方法,而json_encode/decode是最可移植的方法。

如果您考虑这样一个场景:您读/写序列化数据的次数是向非php系统发送数据或从非php系统接收数据的次数的10倍或更多,那么就时间而言,最好还是使用序列化/反序列化,并在序列化之前使用json_encode或json_decode。

其他回答

JSON比PHP的序列化格式更简单、更快,除非:

你正在存储深度嵌套数组: json_decode(): "如果JSON编码的数据大于127个元素,此函数将返回false。" 您存储的对象需要被反序列化为正确的类 您正在与不支持json_decode的旧PHP版本进行交互

这取决于你的优先级。

如果性能是你的绝对驾驶特点,那么无论如何要用最快的。在你做出选择之前,一定要充分了解它们之间的差异

Unlike serialize() you need to add extra parameter to keep UTF-8 characters untouched: json_encode($array, JSON_UNESCAPED_UNICODE) (otherwise it converts UTF-8 characters to Unicode escape sequences). JSON will have no memory of what the object's original class was (they are always restored as instances of stdClass). You can't leverage __sleep() and __wakeup() with JSON By default, only public properties are serialized with JSON. (in PHP>=5.4 you can implement JsonSerializable to change this behavior). JSON is more portable

可能还有其他一些不同之处,我现在想不出来。

一个简单的速度测试来比较两者

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL);

// Make a big, honkin test array
// You may need to adjust this depth to avoid memory limit errors
$testArray = fillArray(0, 5);

// Time json encoding
$start = microtime(true);
json_encode($testArray);
$jsonTime = microtime(true) - $start;
echo "JSON encoded in $jsonTime seconds\n";

// Time serialization
$start = microtime(true);
serialize($testArray);
$serializeTime = microtime(true) - $start;
echo "PHP serialized in $serializeTime seconds\n";

// Compare them
if ($jsonTime < $serializeTime) {
    printf("json_encode() was roughly %01.2f%% faster than serialize()\n", ($serializeTime / $jsonTime - 1) * 100);
}
else if ($serializeTime < $jsonTime ) {
    printf("serialize() was roughly %01.2f%% faster than json_encode()\n", ($jsonTime / $serializeTime - 1) * 100);
} else {
    echo "Impossible!\n";
}

function fillArray( $depth, $max ) {
    static $seed;
    if (is_null($seed)) {
        $seed = array('a', 2, 'c', 4, 'e', 6, 'g', 8, 'i', 10);
    }
    if ($depth < $max) {
        $node = array();
        foreach ($seed as $key) {
            $node[$key] = fillArray($depth + 1, $max);
        }
        return $node;
    }
    return 'empty';
}

仅供参考——如果您想将数据序列化为易于阅读和理解的JSON,但具有更多的压缩和更高的性能,您应该检查messagpack。

我知道这有点晚了,但答案很旧,我想我的基准测试可能会有帮助,因为我刚刚在PHP 7.4中测试过

Serialize/Unserialize比JSON快得多,占用的内存和空间更少,在PHP 7.4中完全胜出,但我不确定我的测试是最有效或最好的。

我基本上创建了一个PHP文件,它返回一个数组,我编码,序列化,然后解码和反序列化。

$array = include __DIR__.'/../tests/data/dao/testfiles/testArray.php';

//JSON ENCODE
$json_encode_memory_start = memory_get_usage();
$json_encode_time_start = microtime(true);

for ($i=0; $i < 20000; $i++) { 
    $encoded = json_encode($array);
}

$json_encode_time_end = microtime(true);
$json_encode_memory_end = memory_get_usage();
$json_encode_time = $json_encode_time_end - $json_encode_time_start;
$json_encode_memory = 
$json_encode_memory_end - $json_encode_memory_start;


//SERIALIZE
$serialize_memory_start = memory_get_usage();
$serialize_time_start = microtime(true);

for ($i=0; $i < 20000; $i++) { 
    $serialized = serialize($array);
}

$serialize_time_end = microtime(true);
$serialize_memory_end = memory_get_usage();
$serialize_time = $serialize_time_end - $serialize_time_start;
$serialize_memory = $serialize_memory_end - $serialize_memory_start;


//Write to file time:
$fpc_memory_start = memory_get_usage();
$fpc_time_start = microtime(true);

for ($i=0; $i < 20000; $i++) { 
    $fpc_bytes = 
    file_put_contents(
        __DIR__.'/../tests/data/dao/testOneBigFile',
        '<?php return '.var_export($array,true).' ?>;'
    );
}

$fpc_time_end = microtime(true);
$fpc_memory_end = memory_get_usage();
$fpc_time = $fpc_time_end - $fpc_time_start;
$fpc_memory = $fpc_memory_end - $fpc_memory_start;


//JSON DECODE
$json_decode_memory_start = memory_get_usage();
$json_decode_time_start = microtime(true);

for ($i=0; $i < 20000; $i++) { 
    $decoded = json_encode($encoded);
}

$json_decode_time_end = microtime(true);
$json_decode_memory_end = memory_get_usage();
$json_decode_time = $json_decode_time_end - $json_decode_time_start;
$json_decode_memory = 
$json_decode_memory_end - $json_decode_memory_start;


//UNSERIALIZE
$unserialize_memory_start = memory_get_usage();
$unserialize_time_start = microtime(true);

for ($i=0; $i < 20000; $i++) { 
    $unserialized = unserialize($serialized);
}

$unserialize_time_end = microtime(true);
$unserialize_memory_end = memory_get_usage();
$unserialize_time = $unserialize_time_end - $unserialize_time_start;
$unserialize_memory = 
$unserialize_memory_end - $unserialize_memory_start;


//GET FROM VAR EXPORT:
$var_export_memory_start = memory_get_usage();
$var_export_time_start = microtime(true);

for ($i=0; $i < 20000; $i++) { 
    $array = include __DIR__.'/../tests/data/dao/testOneBigFile';
}

$var_export_time_end = microtime(true);
$var_export_memory_end = memory_get_usage();
$var_export_time = $var_export_time_end - $var_export_time_start;
$var_export_memory = $var_export_memory_end - $var_export_memory_start;

结果:

Var输出长度:11447 序列化长度:11541 Json编码长度:11895 文件放内容字节:11464

Json编码时间:1.9197590351105 序列化时间:0.160325050354 FPC时间:6.2793469429016

Json编码内存:12288 序列化内存:12288 FPC内存:0

JSON解码时间:1.7493588924408 UnSerialize Time: 0.19309520721436 Var导出和包括:3.1974139213562

JSON解码内存:16384 反序列化内存:14360 Var Export and Include: 192

在你做出最终决定之前,请注意JSON格式对于关联数组是不安全的——json_decode()将它们作为对象返回:

$config = array(
    'Frodo'   => 'hobbit',
    'Gimli'   => 'dwarf',
    'Gandalf' => 'wizard',
    );
print_r($config);
print_r(json_decode(json_encode($config)));

输出是:

Array
(
    [Frodo] => hobbit
    [Gimli] => dwarf
    [Gandalf] => wizard
)
stdClass Object
(
    [Frodo] => hobbit
    [Gimli] => dwarf
    [Gandalf] => wizard
)