Abstract
Following up from T156364: Warning: Empty regular expression in /srv/mediawiki/php-1.29.0-wmf.9/includes/parser/DateFormatter.php on line 200, when the signature of a php class changes, deploying the new version can result in some unexpected behavior. The problem arises when cached instances having the old signature are unserialized in the new environment.
Hence one can serialize to the cache a class that has a property foo marked public. When later the code is updated and the visibility of foo is made private, unserializing the old version produces an object having two foo property:
- A public foo set by unserialize with the expected value
- A private foo that comes from the new class definition and NULL
Trying to access foo PHP obey to the new class definition and retrieve the private one. Hence NULL instead of the value expected.
Repro
Mini case:
<?php # Given two classes with the same property name but different visibility class WithPublic { public $property; function __construct( $p ) { $this->property = $p; } function getProperty() { print $this->property; } } class WithPrivate { private $property; function __construct( $p ) { $this->property = $p; } function getProperty() { print $this->property; } } $priv = new WithPrivate( 'value' ); # Lets pretend it is held in a permanent cache, eg Memcached $cache = serialize( $priv ); # Later on NEW code is deployed which change the property signature to public. # Simulate the class changed: $mut_priv_to_pub = unserialize( str_replace( '11:"WithPrivate"', '10:"WithPublic"', $cache) ); var_dump( $mut_priv_to_pub ); # class WithPublic#4 (2) { # public $property => # NULL <--- from class signature # private $property => # string(5) "value" <--- from unserialize() # } var_export( $mut_priv_to_pub->getProperty() ); # On Zend PHP: NULL # On HHVM 3.15.4, 3.17.1: valueNULL `
Details
Some relevant details extracted from T156364: