PHP的“o”序列化格式是用来干什么的?

9
PHP 7.4不兼容的更改列表包含以下注意事项

序列化

已删除o序列化格式。由于它从未由PHP生成,因此这可能只会破坏手动创建字符串的反序列化。

(请注意,这是指小写字母o,而不是用于对象序列化的大写字母O格式。)

似乎PHP的serialize()函数从未生成过这个,但存在这个注释的事实意味着unserialize()函数曾经识别过它。

我已完成一个小测试fiddle (3v4l.org),显示这不仅仅是大写字母O的同义词,这是一个明显的可能性。

在PHP中,小提琴通过输出的错误消息差异来暴露PHP的更改。在PHP >= 7.4中,我们会在位置0(遇到o的位置)收到一个错误,而在7.4之前,错误会在位置5(数据所在位置)报告。这意味着识别了o,但数据格式不正确,这与我已经推断出的相符。
那么,o序列化格式是什么,它反序列化为什么,为什么PHP支持这样的功能,如果它实际上没有生成它呢?

相关的吗?http://www.phpinternalsbook.com/php5/classes_objects/serialization.html - Caramiriel
@Caramiriel 不是的。我熟悉那个页面——它是关于 PHP 序列化内部的一个很好的资源——但它根本没有提到小写字母 o 的符号表示法。 - HappyDog
1个回答

18

最初,PHP 3 使用 o:<num_fields>:{<fields>} 序列化对象。

以下程序适用于可以从php.net/releases/index.php下载的 PHP 4.0.0 版本(Windows 二进制文件仍然可在 Windows 10 上使用!):

<?php

var_dump(unserialize('o:0:{}'));

输出:

X-Powered-By: PHP/4.0.0
Content-type: text/html

object(stdClass)(0) {
}

我可以追溯到原始对象序列化格式的实现,它在1999年的这个提交中得以体现。 请参阅php3api_var_serialize

同年晚些时候,为了PHP 4的准备工作,对象序列化格式改变,包括被序列化的对象的类名。 此提交将序列化格式更改为o:<classname_length>:"<class_name>":<num_fields>:{<fields>}

这使得PHP3和PHP4的输出不兼容:PHP4无法反序列化使用PHP3序列化的对象。 因此,另添加了一个提交,将o更改为O(小写字母o变成大写字母O)。 o仍然受unserialize()支持,以反序列化使用PHP3序列化的对象,但serialize()不再使用o

在2000年,序列化/反序列化代码进行了重构,导致我们今天看到的文件

可能发生的情况是,兼容性层在某个地方中断了,而没有人关心PHP3的兼容性是否修复。 最初的代码已经超过15年没有与任何PHP版本兼容了。


这是一个非常有用的答案,它指出了小o符号的具体用途。虽然它没有回答问题的“为什么”部分,但也许这已经随着时间的流逝而消失了。我会再等一段时间,如果没有人能够提供更多信息,我可能会接受这个答案。 - HappyDog
@HappyDog 我深入研究了旧的PHP代码库后更新了答案。我仍然不确定是否回答了你的问题,但现在它应该很接近了 :) - Pieter van den Ham
5
哇——您的更新真是太棒了!这个回答提供了如此详细的历史信息,正是我所需要的。实际上,它非常好,我甚至会为此奖励一份悬赏,尽管您的回答已经发布了! - HappyDog
赏金已发放。我还添加了一条注释到 PHP 迁移说明中,引用了你的答案:https://www.php.net/manual/en/migration74.incompatible.php#125717 - HappyDog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接