php - (un)serialize() 的改变行为?

标签 php serialization private php-7 arrayobject

EDIT: Problem is a documented php bug by now: https://bugs.php.net/bug.php?id=71617 thanks to for finding that one @Danack

我刚刚将应用程序从 PHPH 5.5 迁移到 PHP 7,在序列化对象时偶然发现了一些奇怪的行为。

我已尝试将其简化为最小、完整且可验证的示例,可以在 http://sandbox.onlinephpfunctions.com/code/e926a7398119ea715531cafe4ce6a22c329e53b8 找到

问题是如果一个类扩展ArrayObject那么如果你 serialize() 然后 unserialize() 该对象,那么所有私有(private)属性似乎都消失了:

  1. 创建一个具有私有(private)属性和该属性的 getter/setter 方法的类
  2. 创建该类的一个对象
  3. 通过setter方法设置私有(private)属性
  4. serialize() 对象
  5. unserialize() 第 4 步的结果
  6. 调用私有(private)属性的getter方法,结果取决于你的PHP版本
    • PHP 5.3 - PHP 5.6:结果是在第 3 步中设置的值
    • PHP 7:结果为空

我已尝试将其简化为最小、完整且可验证的示例,可以在 http://sandbox.onlinephpfunctions.com/code/e926a7398119ea715531cafe4ce6a22c329e53b8 找到您可以在其中使用不同的 PHP 版本测试代码。

<?php
class demoStdObject {
    public $public = ''; protected $protected = ''; private $private = '';

    public function getPublic() { return $this->public; }    
    public function getProtected() { return $this->protected; }    
    public function getPrivate() { return $this->private; }        
    public function setPublic($public) { $this->public = $public; }    
    public function setProtected($protected) { $this->protected = $protected; }    
    public function setPrivate($private) { $this->private = $private; }
}

class demoArrayObject extends ArrayObject {
    public $public = ''; protected $protected = ''; private $private = '';
    public function getPublic() { return $this->public; }    
    public function getProtected() { return $this->protected; }    
    public function getPrivate() { return $this->private; }        
    public function setPublic($public) { $this->public = $public; }    
    public function setProtected($protected) { $this->protected = $protected; }    
    public function setPrivate($private) { $this->private = $private; }
}


$arrayObject = new demoArrayObject();
$stdObject = new demoStdObject();

testSerialize($arrayObject);
echo str_repeat('-',30) . "\n";
testSerialize($stdObject);

function testSerialize($object) {
  $object->setPublic('public');
  $object->setProtected('protected');
  $object->setPrivate('private');

  $serialized = serialize($object);

  $unserialized = unserialize($serialized);

  echo get_class($object) . ":\n";
  echo $unserialized->getPublic() . "\n";
  echo $unserialized->getProtected() . "\n";
  echo $unserialized->getPrivate() . "\n";
}

PHP 5.6 的输出:

demoArrayObject:
public
protected
private
------------------------------
demoStdObject:
public
protected
private

PHP 7 的输出:

demoArrayObject:
public
protected

------------------------------
demoStdObject:
public
protected
private

我找不到任何与 serialize()unserialize()ArrayObject 类相关的记录更改,所以我想知道发生了什么在。这是一个错误吗?未记录的功能? ;-)

因为我们在项目中做了很多 serialize()/unserialize() 我真的需要确保 PHP 7 的行为与 PHP 5.3 100% 兼容+ 行为。

问题:如何让 PHP 7 的行为像 PHP 5.3+ 一样??

最佳答案

尽管下一个版本的 PHP 已修复此问题,但您的代码依赖于未记录的行为这一事实是一个称为“Programming by Coincidence”的错误。来自精品文章:

How to Program by Coincidence

Suppose Fred is given a programming assignment. Fred types in some code, tries it, and it seems to work. Fred types in some more code, tries it, and it still seems to work. After several weeks of coding this way, the program suddenly stops working, and after hours of trying to fix it, he still doesn’t know why. Fred may well spend a significant amount of time chasing this piece of code around without ever being able to fix it. No matter what he does, it just doesn’t ever seem to work right.

Accidents of Implementation

Accidents of implementation are things that happen simply because that’s the way the code is currently written. You end up relying on undocumented error or boundary conditions.

在这种情况下,无法保证当您扩展 ArrayObject 时子类的值将被正确反序列化。

要么使用组合而不是继承会更安全,或者在子方法上编写序列化/反序列化方法将允许您控制序列化/反序列化。或者,不使用序列化/反序列化,而是使用您自己的界面也比“神奇”的内部方法更可预测。

关于php - (un)serialize() 的改变行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35529510/

相关文章:

java - 如果方法未标记为公共(public)(所有类都在同一个文件中),程序将给出错误

scala - 为什么 `private val` 和 `private final val` 不同?

php - Laravel 返回response()->json() 而不是只返回一个数组

javascript - 我的 Ajax 调用。总是返回错误

php - PHP的curl不加载整页内容而只加载gif

Python:使用 `pickle`或 `marshal`与使用 `re`的性能比较

java - Gson序列化字段仅当不为空或不为空时

php - Javascript - If 语句的条件依赖于 2 个单独的表单 ID

java - 如果您的 Serializable 类包含一个不可序列化的成员,会发生什么情况?你如何解决它?

c++ - 构造函数 Parent 在构造函数 Child 的初始化列表中被调用