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

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

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

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


当前回答

这取决于你的优先级。

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

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';
}

其他回答

我也做了一个小的基准测试。结果是一样的。但是我需要解码性能。我注意到,就像上面几个人说的,unserialize比json_decode快。反序列化大约占用json_decode时间的60-70%。所以结论很简单: 当需要编码时的性能时,使用json_encode,当需要解码时的性能时,使用unserialize。因为你不能合并这两个功能,你必须做出选择,你需要更多的性能。

我在pseudo中的基准:

用一些随机键和值定义数组$arr 对于x < 100;x + +;序列化和json_encode $arr的array_rand 对于y < 1000;y + +;Json_decode json编码的string - calc时间 对于y < 1000;y + +;取消序列化的string - calc时间 回声更快的结果

平均而言:unserialize赢得了96次胜过json_decode的4次。平均约1.5ms超过2.5ms。

我曾经写过一篇关于这个主题的博文:“缓存一个大数组:JSON,序列化还是var_export?”在这篇文章中,我们展示了序列化是大小数组的最佳选择。对于非常大的数组(> 70MB), JSON是更好的选择。

我建议您使用超级缓存,这是一种不使用json_encode或序列化的文件缓存机制。与其他PHP缓存机制相比,它使用简单,速度非常快。

https://packagist.org/packages/smart-php/super-cache

Ex:

<?php
require __DIR__.'/vendor/autoload.php';
use SuperCache\SuperCache as sCache;

//Saving cache value with a key
// sCache::cache('<key>')->set('<value>');
sCache::cache('myKey')->set('Key_value');

//Retrieving cache value with a key
echo sCache::cache('myKey')->get();
?>

我知道这有点晚了,但答案很旧,我想我的基准测试可能会有帮助,因为我刚刚在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_decode/encode似乎比序列化/反序列化BUT更快 如果执行var_dump,序列化对象的类型将被更改。 如果出于某种原因想要保留类型,请使用serialize!

(例如stdClass vs array)

序列化/非系列化:

Array cache:
array (size=2)
  'a' => string '1' (length=1)
  'b' => int 2
Object cache:
object(stdClass)[8]
  public 'field1' => int 123
This cache:
object(Controller\Test)[8]
  protected 'view' => 

JSON 编码/解码

Array cache:
object(stdClass)[7]
  public 'a' => string '1' (length=1)
  public 'b' => int 2
Object cache:
object(stdClass)[8]
  public 'field1' => int 123
This cache:
object(stdClass)[8]

正如你所看到的json_encode/decode将所有转换为stdClass,这不是很好,对象信息丢失…所以根据需要来决定,特别是如果它不仅仅是数组……