ChatGPT解决这个技术问题 Extra ChatGPT

存储 PHP 数组的首选方法(json_encode 与序列化)

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

在这个文本文件中将数组存储为 JSON 或 PHP 序列化数组会更有效吗?我环顾四周,似乎在最新版本的 PHP (5.3) 中,json_decode 实际上比 unserialize 快。

我目前倾向于将数组存储为 JSON,因为我觉得如果必要的话它更容易被人类阅读,它可以在 PHP 和 JavaScript 中使用,而且几乎不需要付出任何努力,而且根据我的阅读,它甚至可能是解码速度更快(但不确定编码)。

有谁知道任何陷阱?任何人都有很好的基准来展示这两种方法的性能优势吗?

为什么不简单地做类似的事情: $array = array('foo' => 'bar'); file_put_contents('foo.php', "<?php return ".var_export($array, true) . ";"); 。和 。 $array = file_get_contents('foo.php'))); 当然,如果这是针对更大的数据量,我可能会选择.... CSV。所以也许不是最性感的——但出于某种原因,它的存在时间比我们都长——而且 PHP 对非常大的数据集的部分或流式访问提供了出色的支持。

T
T.Todua

取决于你的优先级。

如果性能是您的绝对驾驶特性,那么一定要使用最快的。在做出选择之前,请确保您对差异有充分的了解

与 serialize() 不同,您需要添加额外的参数以保持 UTF-8 字符不变: json_encode($array, JSON_UNESCAPED_UNICODE) (否则它将 UTF-8 字符转换为 Unicode 转义序列)。

JSON 将不记得对象的原始类是什么(它们总是作为 stdClass 的实例恢复)。

您不能将 __sleep() 和 __wakeup() 与 JSON 结合使用

默认情况下,只有公共属性使用 JSON 序列化。 (在 PHP>=5.4 中你可以实现 JsonSerializable 来改变这种行为)。

JSON 更便携

可能还有其他一些我目前无法想到的差异。

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

<?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 将 UTF-8 字符转换为 Unicode 转义序列。”不再一定是真的:我们现在有 JSON_UNESCAPED_UNICODE
差不多 5 年后,我再次运行测试(只是 json_encode),它的平均速度比现在的序列化快 131%。因此,在 5.4.x 中,与 5.3.x 相比,该功能必须有一些相当不错的改进。具体来说,我在 CentOS 6 上运行 5.4.24。所以,为 JSON 好!
在我的情况下,我们编码一次并解码很多,因此我们对 json_decode 与 unserialize 进行了基准测试,结果是 JSON dcoded 在 0.06662392616272 秒内
PHP 在 0.093269109725952 秒内未序列化
json_decode() 比 unserialize() 快大约 39.99%
有趣:如果您在 3v4l.org 上运行此代码,最新的 PHP7 开发版本运行序列化比 json_encode 快:“serialize() 大约比 json_encode() 快 76.53%”
2017 年,PHP 7.1 和 serialize() was roughly 35.04% faster than json_encode()
G
Greg

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

您正在存储深度嵌套的数组:json_decode():“如果 JSON 编码的数据深度超过 127 个元素,此函数将返回 false。”

您将需要反序列化的对象存储为正确的类

您正在与不支持 json_decode 的旧 PHP 版本进行交互


很好的答案。哈哈,127级深好像有点疯了;谢天谢地,我最多只能跑 2-3 次。您是否有任何数据来支持 json_decode/json_encode 比 unserialize/serialize 更快的事实?
不久前我确实对其进行了测试,并且 json 出来的速度更快——虽然我没有数据了。
“5.3.0 增加了可选深度。默认递归深度从 128 增加到 512”
我会在上面的列表中再添加一项:如果您的数据可能包含无效的 UTF-8 字节序列,则不应使用 json_encode()。它只是为此类数据返回 false。例如: var_dump(json_encode("\xEF\xEF"));
一般来说,它更快是不正确的。如果您有一个包含大约 500 个条目的小数组,那么反序列化/序列化实际上比 json_decode/json_encode (PHP 5.6.19) 快 200-400%
u
user8555937

我写了一篇关于这个主题的博文:“Cache a large array: JSON, serialize or var_export?”。在这篇文章中,表明序列化是小型到大型数组的最佳选择。对于非常大的数组(> 70MB),JSON 是更好的选择。


该链接不再可用。
谢谢,驼鹿,我已经更新了链接。虽然这篇文章已经有将近 6 年的历史了,对于当前的 PHP 版本来说可能不是那么准确。
我做了一些测试并制作了一个简单的函数来测试它,使用大数组(使用 Peter Bailey 的函数),json_encode() 的速度大约提高了 80% 到 150%(它确实在上升那里)比 serialize(),大约 300 次迭代。但是在使用较小的数组 (array("teams" => array(1 => array(4 arrays of players), 2 => array(4 arrays of players)))) 时,我确实使用了 750,000 次迭代进行了测试,在这种情况下,serialize() 的速度大约提高了 6% 到 10%。我的函数取所有迭代的平均时间并进行比较。我可能会把它贴在这里作为答案之一
如果数据仅由 PHP 使用,则 var_export 是我的事。只需要小心包含思想中可能出现的语法错误。
博客不再存在
D
David Goodwin

您可能还对 https://github.com/phadej/igbinary 感兴趣 - 它为 PHP 提供了不同的序列化“引擎”。

我的随机/任意“性能”数据,在 64 位平台上使用 PHP 5.3.5 显示:

JSON:

JSON 在 2.180496931076 秒内编码

JSON 在 9.8368630409241 秒内解码

序列化的“字符串”大小:13993

原生 PHP:

PHP 在 2.9125759601593 秒内序列化

PHP 在 6.4348418712616 秒内反序列化

序列化的“字符串”大小:20769

二进制:

WIN igbinary 在 1.6099879741669 秒内序列化

WIN igbinrary 在 4.7737920284271 秒内反序列化

WIN 序列化“字符串”大小:4467

因此,igbinary_serialize() 和 igbinary_unserialize() 更快,并且使用更少的磁盘空间。

我使用了上面的 fillArray(0, 3) 代码,但使数组键更长的字符串。

igbinary 可以存储与 PHP 的本机序列化相同的数据类型(因此对象等没有问题),如果您愿意,可以告诉 PHP5.3 将其用于会话处理。

另请参阅 http://ilia.ws/files/zendcon_2010_hidden_features.pdf - 特别是 2016 年 14 月 15 日的幻灯片


今天怎么样?现在我们有了 PHP 7.*.* 甚至 PHP 8.*.*?我们应该尝试 igbinary 吗?谢谢!
B
Blunk

刚刚测试了序列化和 json 编码和解码,加上它将存储的字符串的大小。

JSON encoded in 0.067085981369 seconds. Size (1277772)
PHP serialized in 0.12110209465 seconds. Size (1955548)
JSON decode in 0.22470498085 seconds
PHP serialized in 0.211947917938 seconds
json_encode() was roughly 80.52% faster than serialize()
unserialize() was roughly 6.02% faster than json_decode()
JSON string was roughly 53.04% smaller than Serialized string

我们可以得出结论,JSON 编码更快并产生更小的字符串,但反序列化更快地解码字符串。


我不知道为什么人们总是用这么小的数据集进行性能测试。这样做你有所有的开销,你的结果会增加错误。如果人们对性能感兴趣,那可能是因为他们有一个非常大的数据集,因为一次获得微秒是没有意义的。
我经常迭代许多小数据集。对于数百个小型数据集,每个数据集获得 1mS 仍然很有趣。
@YannSagon 即使数据集很小,进行性能测试也是有意义的。如果只有大约一微秒,您应该如何在测试前知道?
那我一定是做错了什么?因为我刚刚做了基准测试,而 Serialise 和 unserialise 更快,更小的字符串
J
Jordan S. Jones

如果您正在缓存您最终想要在以后“包含”的信息,您可能需要尝试使用 var_export。这样,您只会在“序列化”中受到打击,而不是在“反序列化”中受到打击。


这很可能是最快的方法。我在 SO“PHP - fast serialize/unserialize”上写了一个示例:stackoverflow.com/questions/2545455/…
J
Jeff Whiting

我增加了测试以包括反序列化性能。这是我得到的数字。

Serialize

JSON encoded in 2.5738489627838 seconds
PHP serialized in 5.2861361503601 seconds
Serialize: json_encode() was roughly 105.38% faster than serialize()


Unserialize

JSON decode in 10.915472984314 seconds
PHP unserialized in 7.6223039627075 seconds
Unserialize: unserialize() was roughly 43.20% faster than json_decode() 

所以 json 似乎编码速度更快,但解码速度慢。因此,这可能取决于您的应用程序以及您最期望做的事情。


C
Community

非常好的话题,在阅读了几个答案之后,我想分享我在这个主题上的实验。

我有一个用例,几乎每次我与数据库交谈时都需要查询一些“巨大”的表(不要问为什么,只是一个事实)。数据库缓存系统不合适,因为它不会缓存不同的请求,所以我想到了 php 缓存系统。

我试过 apcu 但它不符合需要,在这种情况下内存不够可靠。下一步是通过序列化缓存到文件中。

表有 18 列的 14355 个条目,这些是我在读取序列化缓存时的测试和统计信息:

JSON:

正如大家所说,json_encode/json_decode 的主要不便之处在于它将所有内容都转换为 StdClass 实例(或对象)。如果你需要循环它,将它转换为一个数组是你可能会做的,是的,它增加了转换时间

平均时间:780.2 毫秒;内存使用:41.5MB;缓存文件大小:3.8MB

消息包

@hutch 提到了 msgpack。漂亮的网站。让我们试一试好吗?

平均时间:497 毫秒;内存使用:32MB;缓存文件大小:2.8MB

这更好,但需要新的扩展;编译有时害怕的人...

二进制

@GingerDog 提到 igbinary。请注意,我之所以设置 igbinary.compact_strings=Off,是因为我更关心阅读性能而不是文件大小。

平均时间:411.4 毫秒;内存使用:36.75MB;缓存文件大小:3.3MB

比味精包好。不过,这个也需要编译。

序列化/反序列化

平均时间:477.2 毫秒;内存使用:36.25MB;缓存文件大小:5.9MB

比 JSON 更好的性能,数组越大,json_decode 越慢,但你已经是新的了。

这些外部扩展正在缩小文件大小,并且在纸上看起来很棒。数字不会说谎*。如果您获得与使用标准 PHP 函数几乎相同的结果,那么编译扩展的意义何在?

我们还可以推断,根据您的需求,您会选择与其他人不同的东西:

IgBinary 真的很好,性能比 MsgPack 好

Msgpack 更擅长压缩数据(请注意,我没有尝试过 igbinary compact.string 选项)。

不想编译?使用标准。

就是这样,另一种序列化方法比较来帮助您选择一个!

*使用 PHPUnit 3.7.31、php 5.5.10 测试 - 仅使用标准硬盘和旧双核 CPU 解码 - 10 次相同用例测试的平均数,您的统计数据可能不同


为什么不将标志传递给 json_decode 以强制返回数组?
因为它很慢。我没有对此进行测试,但我认为简单地强制从 php 更改类型会更快。
我只知道创建数组比 php 中的对象快得多。
所以你在谈论 json_decode($object, true),基本上它会和 (array) json_decode($object) 做同样的事情,但会递归,所以这将是相同的行为,并且在这两种情况下都会产生很大的成本。请注意,我没有测试 StdClassarray 之间的性能差异,但这并不是重点。
我确信这是另一个成本,因为它是在没有对象的情况下在较低级别上完成的。
u
urraka

似乎序列化是我要使用的一个,原因有两个:

有人指出,反序列化比 json_decode 更快,“读”的情况听起来比“写”的情况更有可能。

当字符串包含无效的 UTF-8 字符时,我遇到了 json_encode 问题。发生这种情况时,字符串最终为空,导致信息丢失。


M
Mr. Sox

我已经在一个相当复杂的、温和嵌套的多重哈希上对此进行了非常彻底的测试,其中包含各种数据(字符串、NULL、整数),并且序列化/反序列化最终比 json_encode/json_decode 快得多。

json 在我的测试中的唯一优势是它的“打包”尺寸更小。

这些是在 PHP 5.3.3 下完成的,如果您需要更多详细信息,请告诉我。

这是测试结果,然后是生成它们的代码。我无法提供测试数据,因为它会泄露我不能在野外泄露的信息。

JSON encoded in 2.23700618744 seconds
PHP serialized in 1.3434419632 seconds
JSON decoded in 4.0405561924 seconds
PHP unserialized in 1.39393305779 seconds

serialized size : 14549
json_encode size : 11520
serialize() was roughly 66.51% faster than json_encode()
unserialize() was roughly 189.87% faster than json_decode()
json_encode() string was roughly 26.29% smaller than serialize()

//  Time json encoding
$start = microtime( true );
for($i = 0; $i < 10000; $i++) {
    json_encode( $test );
}
$jsonTime = microtime( true ) - $start;
echo "JSON encoded in $jsonTime seconds<br>";

//  Time serialization
$start = microtime( true );
for($i = 0; $i < 10000; $i++) {
    serialize( $test );
}
$serializeTime = microtime( true ) - $start;
echo "PHP serialized in $serializeTime seconds<br>";

//  Time json decoding
$test2 = json_encode( $test );
$start = microtime( true );
for($i = 0; $i < 10000; $i++) {
    json_decode( $test2 );
}
$jsonDecodeTime = microtime( true ) - $start;
echo "JSON decoded in $jsonDecodeTime seconds<br>";

//  Time deserialization
$test2 = serialize( $test );
$start = microtime( true );
for($i = 0; $i < 10000; $i++) {
    unserialize( $test2 );
}
$unserializeTime = microtime( true ) - $start;
echo "PHP unserialized in $unserializeTime seconds<br>";

$jsonSize = strlen(json_encode( $test ));
$phpSize = strlen(serialize( $test ));

echo "<p>serialized size : " . strlen(serialize( $test )) . "<br>";
echo "json_encode size : " . strlen(json_encode( $test )) . "<br></p>";

//  Compare them
if ( $jsonTime < $serializeTime )
{
    echo "json_encode() was roughly " . number_format( ($serializeTime / $jsonTime - 1 ) * 100, 2 ) . "% faster than serialize()";
}
else if ( $serializeTime < $jsonTime )
{
    echo "serialize() was roughly " . number_format( ($jsonTime / $serializeTime - 1 ) * 100, 2 ) . "% faster than json_encode()";
} else {
    echo 'Unpossible!';
}
    echo '<BR>';

//  Compare them
if ( $jsonDecodeTime < $unserializeTime )
{
    echo "json_decode() was roughly " . number_format( ($unserializeTime / $jsonDecodeTime - 1 ) * 100, 2 ) . "% faster than unserialize()";
}
else if ( $unserializeTime < $jsonDecodeTime )
{
    echo "unserialize() was roughly " . number_format( ($jsonDecodeTime / $unserializeTime - 1 ) * 100, 2 ) . "% faster than json_decode()";
} else {
    echo 'Unpossible!';
}
    echo '<BR>';
//  Compare them
if ( $jsonSize < $phpSize )
{
    echo "json_encode() string was roughly " . number_format( ($phpSize / $jsonSize - 1 ) * 100, 2 ) . "% smaller than serialize()";
}
else if ( $phpSize < $jsonSize )
{
    echo "serialize() string was roughly " . number_format( ($jsonSize / $phpSize - 1 ) * 100, 2 ) . "% smaller than json_encode()";
} else {
    echo 'Unpossible!';
}

我刚刚用 PHP 5.4.12 进行了类似的测试,发现了类似的结果: {un,}serialize 更快。我的数据是嵌套 3 级深度的哈希(900k 序列化)。
J
Jelmer

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

我的伪基准:

使用一些随机键和值定义数组 $arr

对于 x < 100; x++;序列化和 json_encode $arr 的 array_rand

对于 y < 1000;是++; json_decode json 编码的字符串 - 计算时间

对于 y < 1000;是++;反序列化序列化的字符串 - 计算时间

回显更快的结果

平均而言:反序列化赢得了 96 次超过 json_decode 的 4 倍。在 2.5 毫秒内平均大约 1.5 毫秒。


佚名

我知道这已经很晚了,但是答案已经很老了,我认为我的基准测试可能会有所帮助,因为我刚刚在 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 反序列化时间:0.19309520721436 Var 导出和包含:3.1974139213562

JSON 解码内存:16384 反序列化内存:14360 Var 导出和包含:192


P
Pink Code

在此处查看结果(对于将 PHP 代码放入 JS 代码框中的黑客行为感到抱歉):

http://jsfiddle.net/newms87/h3b0a0ha/embedded/result/

结果:在 PHP 5.4 中,serialize()unserialize() 在不同大小的数组上都明显更快。

我针对真实世界的数据制作了一个测试脚本,用于比较 json_encode 与 serialize 以及 json_decode 与 unserialize。测试在生产中电子商务网站的缓存系统上运行。它只是获取已经在缓存中的数据,并测试对所有数据进行编码/解码(或序列化/反序列化)的时间,并将其放在一个易于查看的表中。

我在 PHP 5.4 共享主机服务器上运行它。

结果非常明确,对于这些从大到小的数据集,序列化和反序列化是明显的赢家。特别是对于我的用例,json_decode 和 unserialize 对缓存系统来说是最重要的。反序列化在这里几乎是无处不在的赢家。它通常是 json_decode 的 2 到 4 倍(有时是 6 或 7 倍)。

注意到@peter-bailey 的结果差异很有趣。

这是用于生成结果的 PHP 代码:

<?php

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

function _count_depth($array)
{
    $count     = 0;
    $max_depth = 0;
    foreach ($array as $a) {
        if (is_array($a)) {
            list($cnt, $depth) = _count_depth($a);
            $count += $cnt;
            $max_depth = max($max_depth, $depth);
        } else {
            $count++;
        }
    }

    return array(
        $count,
        $max_depth + 1,
    );
}

function run_test($file)
{
    $memory     = memory_get_usage();
    $test_array = unserialize(file_get_contents($file));
    $memory     = round((memory_get_usage() - $memory) / 1024, 2);

    if (empty($test_array) || !is_array($test_array)) {
        return;
    }

    list($count, $depth) = _count_depth($test_array);

    //JSON encode test
    $start            = microtime(true);
    $json_encoded     = json_encode($test_array);
    $json_encode_time = microtime(true) - $start;

    //JSON decode test
    $start = microtime(true);
    json_decode($json_encoded);
    $json_decode_time = microtime(true) - $start;

    //serialize test
    $start          = microtime(true);
    $serialized     = serialize($test_array);
    $serialize_time = microtime(true) - $start;

    //unserialize test
    $start = microtime(true);
    unserialize($serialized);
    $unserialize_time = microtime(true) - $start;

    return array(
        'Name'                   => basename($file),
        'json_encode() Time (s)' => $json_encode_time,
        'json_decode() Time (s)' => $json_decode_time,
        'serialize() Time (s)'   => $serialize_time,
        'unserialize() Time (s)' => $unserialize_time,
        'Elements'               => $count,
        'Memory (KB)'            => $memory,
        'Max Depth'              => $depth,
        'json_encode() Win'      => ($json_encode_time > 0 && $json_encode_time < $serialize_time) ? number_format(($serialize_time / $json_encode_time - 1) * 100, 2) : '',
        'serialize() Win'        => ($serialize_time > 0 && $serialize_time < $json_encode_time) ? number_format(($json_encode_time / $serialize_time - 1) * 100, 2) : '',
        'json_decode() Win'      => ($json_decode_time > 0 && $json_decode_time < $serialize_time) ? number_format(($serialize_time / $json_decode_time - 1) * 100, 2) : '',
        'unserialize() Win'      => ($unserialize_time > 0 && $unserialize_time < $json_decode_time) ? number_format(($json_decode_time / $unserialize_time - 1) * 100, 2) : '',
    );
}

$files = glob(dirname(__FILE__) . '/system/cache/*');

$data = array();

foreach ($files as $file) {
    if (is_file($file)) {
        $result = run_test($file);

        if ($result) {
            $data[] = $result;
        }
    }
}

uasort($data, function ($a, $b) {
    return $a['Memory (KB)'] < $b['Memory (KB)'];
});

$fields = array_keys($data[0]);
?>

<table>
    <thead>
    <tr>
        <?php foreach ($fields as $f) { ?>
            <td style="text-align: center; border:1px solid black;padding: 4px 8px;font-weight:bold;font-size:1.1em"><?= $f; ?></td>
        <?php } ?>
    </tr>
    </thead>

    <tbody>
    <?php foreach ($data as $d) { ?>
        <tr>
            <?php foreach ($d as $key => $value) { ?>
                <?php $is_win = strpos($key, 'Win'); ?>
                <?php $color = ($is_win && $value) ? 'color: green;font-weight:bold;' : ''; ?>
                <td style="text-align: center; vertical-align: middle; padding: 3px 6px; border: 1px solid gray; <?= $color; ?>"><?= $value . (($is_win && $value) ? '%' : ''); ?></td>
            <?php } ?>
        </tr>
    <?php } ?>
    </tbody>
</table>

D
Divyang Desai

首先,我更改了脚本以进行更多基准测试(并且还进行了 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) (built: Jan 18 2017 19:13:23) (NTS) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies with Zend OPcache v7.0.14,版权所有 (c) 1999-2016,由 Zend Technologies 提供

我的结果是:

serialize() (wins: 999) 比 json_encode() 快大约 10.98% unserialize() (wins: 987) 大约比 json_decode() 快 33.26% unserialize() (wins: 987) 比数组 json_decode 快大约 48.35% ()

很明显,serialize/unserialize 是最快的方法,而 json_encode/decode 是最便携的。

如果您考虑读取/写入序列化数据的频率是向非 PHP 系统发送或接收数据的 10 倍或更多的场景,那么您最好使用序列化/反序列化并在序列化之前使用 json_encode 或 json_decode在时间方面。


php8.1 -f test.php serialize() (wins: 992) 比 json_encode() 快大约 20.57% unserialize() (wins: 999) 比 json_decode() unserialize() (wins: 999) 快大约 110.41% ) 比数组 json_decode() 快大约 138.71%
$ php7.4 -f test.php serialize() (wins: 970) 比 json_encode() 快大约 7.30% unserialize() (wins: 1000) 比 json_decode() unserialize() (wins: 1000) 快大约 164.96% ) 比数组 json_decode() 快大约 177.39%
t
too much php

在做出最终决定之前,请注意 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
)

的确,你是对的。我的意思是,它毕竟是 is Javascript object 符号!值得庆幸的是,如果您知道您使用 json_encode 编码的是一个关联数组,您可以轻松地将其强制返回到一个数组中,如下所示:$json = json_encode($some_assoc_array); $back_to_array = (array)json_decode($json); 另外值得注意的是,您可以访问对象与 PHP 中的数组方式相同,因此在典型场景中,人们甚至不知道其中的区别。不过好点!
@toumuchphp,对不起,你错了。 json_decode 'bool $assoc = false' 的第二个参数使 json_decode 生成一个数组。 @KyleFarris,这也应该比使用类型转换到数组更快。
答案不正确。当使用 true 作为函数的第二个参数时, json_decode() 将返回关联数组而不是对象。
H
Hutch

仅供参考 - 如果您想将数据序列化为易于阅读和理解的内容(例如 JSON),但具有更高的压缩率和更高的性能,您应该查看 messagepack.


如果只是仅供参考,您最好将其作为评论。
I
Informate.it

如果您想备份数据并在另一台机器上或通过 FTP 恢复数据,JSON 会更好。

例如,如果您将数据存储在 Windows 服务器上,通过 FTP 下载并在 Linux 上恢复它,则使用序列化,由于字符重新编码,它无法再工作,因为序列化存储字符串的长度和 Unicode > UTF-8 对一些 1 字节字符进行转码可能会变成 2 字节长,从而导致算法崩溃。


g
gmadd

THX - 对于这个基准代码:

我用于配置的数组的结果如下所示:JSON 编码为 0.0031511783599854 秒
PHP 序列化 0.0037961006164551 秒
json_encode() 大约比 serialize() JSON 编码 0.0070841312408447 秒快 20.47%
PHP 序列化在 0.0035839080810547 秒内
unserialize()json_encode() 快大约 97.66%

所以 - 在您自己的数据上进行测试。


你的意思是“unserialize() 中的 json_decode() 比 json_encode() 快大约 97.66%”,是吗?
D
David Constantine

如果总结人们在这里所说的话,json_decode/encode 似乎比 serialize/unserialize 更快,但是如果你做 var_dump,序列化对象的类型就会改变。如果出于某种原因您想保留类型,请使用序列化!

(尝试例如 stdClass 与数组)

序列化/反序列化:

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,这不是很好,对象信息丢失了...所以根据需要决定,特别是如果它不仅是数组...


请注意:大多数其他答案都说序列化/反序列化更快。
s
shabeer

我建议你使用 Super Cache,它是一种文件缓存机制,不会使用 json_encodeserialize。与其他 PHP 缓存机制相比,它使用简单且速度非常快。

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

前任:

<?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();
?>

-1。虽然它可能是一个更好的解决方案,但这个答案的任何部分都没有真正回答 OP 的问题。将来,也许尝试回答这个问题,但在底部留下一个建议,即替代解决方案可能值得研究。

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅