PHP:对象数组 - 序列化与 json_encode - 替代方案?

Posted

技术标签:

【中文标题】PHP:对象数组 - 序列化与 json_encode - 替代方案?【英文标题】:PHP: array of objects - serialize vs json_encode - alternatives? 【发布时间】:2013-07-03 14:11:09 【问题描述】:

php 中,我很难在大量对象(100000 多个对象)上使用 serialize/unserialize。这些对象可以有很多不同的类型,但都是基类的后代。

不知何故,当我在对象数组上使用unserialize 时,大约 0,001% 的对象生成错误!而是生成了一个完全不同的对象。这不是随机发生的,而是每次都使用相同的对象。但是如果我改变数组的顺序,它会发生在不同的对象上,所以这对我来说似乎是一个错误。

我切换到json_encode/json_decode,但发现这总是使用stdClass作为对象的类。我通过将每个对象的类名包含为一个属性来解决这个问题,然后使用这个属性构造一个新对象,但是这个解决方案不是很优雅。

var_exporteval 一起使用可以正常工作,但比其他方法慢约3 倍,并且使用更多内存。

现在我的问题是:

什么可能导致错误/错误的对象创建 unserialize ? 有没有更好的方法将json_decode 与对象数组一起使用,以便类以某种方式存储在 json 中 自动? 是否还有其他方法可以在 PHP 中读取/写入大量对象?

更新

我开始相信我的数组数据一定有什么奇怪的地方,因为msgpack_serialize(php 扩展,serialize 的替代品)我得到了同样的错误(但奇怪的是 不是相同的对象生成错误!)。

更新 2

找到了一个解决方案:我不是在整个数组上执行serialize,而是在每个对象上执行,首先是serialize,然后是base64_encode,然后我将每个序列化对象存储为文本文件中的单独一行。这样我就可以生成整个对象数组,然后使用file()unserializebase64_decode 迭代每个对象:不再出现错误!

【问题讨论】:

出现了哪些具体的错误? 不知何故,使用反序列化生成的一些对象实际上是一个完全不同的对象,它也在数组中,但因此生成了两次。因此,一些指向对象的内部指针似乎有问题...... 检查我的答案 Dylan serialize() 更适合大型对象 json_encode 更适合没有资源且您不在乎它们是否正确“唤醒”的对象。 你用什么版本的 php 观察到这个?听起来它可能与bugs.php.net/bug.php?id=66085 有关,如果您在序列化调用中保持对数组项的实时外部引用(例如在全局中),是否修复了不正确的条目。 【参考方案1】:

通过序列化/反序列化函数,连接了 2 个魔术方法。

__sleep()

serialize() 检查你的类是否有一个名为 __sleep() 的函数。如果是这样,则该函数在任何序列化之前执行。它可以清理对象,并且应该返回一个数组,其中包含应该序列化的该对象的所有变量的名称。如果该方法没有返回任何内容,则将 NULL 序列化并发出 E_NOTICE。

通过睡眠,您可以更好地控制序列化操作,您可以传递可序列化的变量并在序列化之前清理资源。

当调用反序列化时,应该提到另一个函数

__wakeup()

__wakeup() 的预期用途是重新建立在序列化期间可能丢失的任何数据库连接并执行其他重新初始化任务。

关于 json_encode()

    它没有魔术方法 __wakeup、__sleep,因此您的控制更少 它不序列化私有属性 对象始终存储为 stdClass Json_encode 比序列化更快

这取决于你的选择,但对于具有数据库连接等的更高级的类,我建议使用 serialize()

【讨论】:

以上是关于PHP:对象数组 - 序列化与 json_encode - 替代方案?的主要内容,如果未能解决你的问题,请参考以下文章

php序列化与反序列化

[极客大挑战 2019]PHP CTF题解与分析

php如何序列化对象数组?

JSON PHP中,Json字符串反序列化成对象/数组的方法

浅析php反序列化漏洞

序列化与JSON