PHP序列化体积大因serialize()冗余标记多,优先用json_encode;嵌套深时选igbinary(小30%~60%);超10KB可msgpack+gzcompress;根本解法是精简数据结构,只存必要字段。

PHP序列化后体积太大?先看是不是用了serialize()直接存
默认用serialize()存数组或对象,会产生大量冗余字符(比如a:3:{i:0;s:5:"hello";i:1;s:6:"world";}里的类型标记、引号、分号)。尤其当键名重复、值含大量数字或短字符串时,膨胀明显。这不是bug,是设计使然——它要保证反序列化100%准确,不压缩、不省略、不推断。
实操建议:
- 确认是否真需要
serialize():如果只是缓存简单键值对(如['user_id'=>123, 'status'=>'active']),优先用json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),体积通常小20%~40% - 避免嵌套过深的对象:
serialize()会完整记录类名、私有属性符号("\0Classname\0prop"),比JSON多出一倍长度 - 测试前先用
strlen(serialize($data))和strlen(json_encode($data))对比,别凭感觉优化
想进一步压缩?igbinary比serialize更紧凑
igbinary是C扩展实现的二进制序列化,不生成可读字符串,直接写类型+长度+原始字节。对含大量整数、重复字符串、深层嵌套的数据,体积常比serialize()小30%~60%,且反序列化更快。
使用前提与注意点:
立即学习“PHP免费学习笔记(深入)”;
- 必须安装
igbinary扩展(pecl install igbinary,并启用extension=igbinary.so) - 不能跨语言互通:PHP用
igbinary_serialize()存的,其他语言读不了;serialize()至少还能被Python的phpserialize库解析 - PHP 8.0+需用
igbinary >= 3.2.1,否则可能触发Segmentation fault - 示例:
$data = ['id' => 12345, 'tags' => ['php', 'cache', 'php']]; $packed = igbinary_serialize($data); // 比 serialize($data) 短得多 $data2 = igbinary_unserialize($packed);
极致省空间:msgpack + gzip两级压缩
当缓存数据量大(如>10KB)、网络或磁盘IO敏感(如Redis内存紧张、文件缓存占满SSD),可组合使用msgpack(更紧凑的二进制格式)和gzcompress()(zlib压缩)。
关键权衡:
-
msgpack本身比igbinary略小,但PHP扩展普及度低,需pecl install msgpack;反序列化速度略慢于igbinary -
gzcompress()压缩率高(尤其文本多时),但CPU开销明显;若缓存命中率>95%,压缩/解压反而拖慢整体响应 - 别用
gzencode():它加了HTTP头,浪费10+字节;gzcompress()才是纯deflate流 - 示例流程:
$raw = msgpack_pack($data); $compressed = gzcompress($raw, 9); // 第二参数1~9,9为最高压缩 // 存$compressed;读取时:$data = msgpack_unpack(gzuncompress($compressed));
别忽略数据结构本身——序列化再省也救不了乱设计
见过最典型的浪费:把整个User对象(含DB连接、日志器、未初始化的关联模型)塞进缓存。哪怕用msgpack+gzip,体积也下不来。真正省空间的第一步,是只存必要字段。
检查清单:
- 序列化前用
array_only($user, ['id', 'name', 'email'])过滤(Laravel)或array_intersect_key($user, array_flip(['id','name']))手动裁剪 - 时间戳统一转
int,别存DateTime对象(serialize()会记全类信息) - 布尔值、null、小整数尽量用原生类型,别包装成字符串(
"1"比1多2个字节,且serialize()里标为s:1:"1"而非i:1) - 如果缓存的是SQL查询结果,考虑用
mysqli_fetch_row()而非fetch_assoc(),返回数字索引数组,序列化后少一半键名存储
压缩算法再强,也压不扁本不该存在的数据。省空间的本质,是让序列化对象尽可能“干净”。










