Posted at

PHPのunserializeでクラスプロパティに変更があった場合

何となく気軽にセッションにオブジェクトを保存していて、クラスに変更があった場合にどうなるのか気になったので動かしてみた。

PHP 7.2


Foo.php

<?php

class Foo
{
private $id;
protected $name;
public $attributes = [];

public function __construct(int $id, string $name, array $attrs)
{
$this->id = $id;
$this->name = $name;
$this->attributes = $attrs;
}
}



serialize.php

<?php

require_once 'Foo.php';
$foo = new Foo(3, 'foo', ['bar' => 'baz', 7]);
echo serialize($foo);


unserialize.php

<?php

error_reporting(-1);
require_once 'Foo.php';
$data = stream_get_contents(STDIN);
var_dump(unserialize($data));

普通にserialize => unserialize を実行するとこうなる。

$ php serialize.php | php unserialize.php

/tmp/php/unserialize.php:5:
class Foo#1 (3) {
private $id =>
int(3)
protected $name =>
string(3) "foo"
public $attributes =>
array(2) {
'bar' =>
string(3) "baz"
[0] =>
int(7)
}
}

プロパティが増えた場合。


Foo1.php

<?php

class Foo
{
private $id;
protected $name;
public $attributes = [];
public $opt;
public function __construct(int $id, string $name, array $attrs, ?string $opt)
{
$this->id = $id;
$this->name = $name;
$this->attributes = $attrs;
$this->opt = $opt;
}
}

$ php serialize.php | php unserialize1.php

/tmp/php/unserialize1.php:8:
class Foo#1 (4) {
private $id =>
int(3)
protected $name =>
string(3) "foo"
public $attributes =>
array(2) {
'bar' =>
string(3) "baz"
[0] =>
int(7)
}
public $opt =>
NULL
}

増えたプロパティが単にnullになる模様。特にエラー等は無い。

プロパティが減った場合、アクセス修飾子が変わった場合は?


Foo2.php

<?php

class Foo
{
protected $id;
public function __construct(int $id)
{
$this->id = $id;
}
}

$ php serialize.php | php unserialize2.php

/tmp/php/unserialize2.php:8:
class Foo#1 (3) {
protected $id =>
int(3)
protected $name =>
string(3) "foo"
public $attributes =>
array(2) {
'bar' =>
string(3) "baz"
[0] =>
int(7)
}
}

protected に変更した$idprotectedに変更された。プロパティごと削除したものはprotectedpublicを維持して復活した。

まあそうなるよねって感じなんだけど、protectedを維持して復活したのが少し意外だった。PHP的には未定義プロパティへの代入と見なしてpublicに変わってもおかしくないような。

この動作はどこかに書いてるんだろうか?

https://php.net/unserialize

https://php.net/oop5.serialization

見つけられなかった。

訓練されたPHPerなら良い感じに復元してくれることを想定してるでしょってことか。

E_NOTICEが出る可能性もあるかなと思ったけど、そもそも復元失敗した場合がE_NOTICEだからプロパティが違ったぐらいじゃエラーにならないか。