¿Comportamiento cambiado de (un) serialize ()?

EDITAR: El problema es un error de php documentado por ahora: https://bugs.php.net/bug.php?id=71617 gracias por encontrar ese @Danack

Solo estoy migrando una aplicación de PHPH 5.5 a PHP 7 y tropecé con algún comportamiento extraño cuando se trata de serializar objetos.

Intenté cocinarlo en un ejemplo mínimo, completo y verificable que se puede encontrar en http://sandbox.onlinephpfunctions.com/code/e926a7398119ea715531cafe4ce6a22c329e53b8

El problema es que si una clase extiende ArrayObject , todas las propiedades privadas parecen desaparecer si serialize() y luego unserialize() ese objeto:

  1. crear una clase con una propiedad privada y método getter / setter para esa propiedad
  2. crea un objeto de esa clase
  3. establecer propiedad privada a través del método setter
  4. serialize() objeto
  5. unserialize() resultado del paso 4
  6. método getter de propiedad privada, el resultado depende de tu versión de PHP
    • PHP 5.3 – PHP 5.6: el resultado es el valor establecido en el paso 3
    • PHP 7: el resultado es nulo

Intenté cocinarlo en un ejemplo mínimo, completo y verificable que se puede encontrar en http://sandbox.onlinephpfunctions.com/code/e926a7398119ea715531cafe4ce6a22c329e53b8, donde puede probar el código con diferentes versiones de PHP.

 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"; } 

Salida para PHP 5.6:

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

Salida para PHP 7:

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

No pude encontrar ningún cambio documentado relacionado con serialize() , unserialize() o la clase ArrayObject , así que me pregunto qué está pasando. ¿Es un error? Característica no documentada? 😉

Como hacemos un montón de serialize() / unserialize() en nuestro proyecto, realmente necesito asegurarme de que el comportamiento de PHP 7 sea 100% compatible con el comportamiento de PHP 5.3+.

Pregunta: ¿Cómo puedo hacer que PHP 7 se comporte como PHP 5.3+?

Aunque esto se soluciona para la próxima versión de PHP, el hecho de que su código se base en un comportamiento no documentado es un error conocido como ” Progtwigción por coincidencia “. Del artículo fino:

Cómo progtwigr por coincidencia

Supongamos que Fred recibe una asignación de progtwigción. Fred escribe algún código, lo intenta y parece funcionar. Fred teclea más código, lo intenta y parece que todavía funciona. Después de varias semanas de encoding de esta manera, el progtwig deja de funcionar repentinamente, y después de horas de intentar solucionarlo, todavía no sabe por qué. Fred bien puede pasar una gran cantidad de tiempo persiguiendo esta pieza de código sin siquiera poder arreglarlo. No importa lo que haga, simplemente parece que nunca funciona bien.

Accidentes de implementación

Los accidentes de implementación son cosas que ocurren simplemente porque esa es la forma en que el código se escribe actualmente. Usted termina confiando en un error no documentado o condiciones de frontera.

En este caso, no hay garantía de que cuando extienda ArrayObject, los valores de la clase hija se desenergicen correctamente.

Usar composición en lugar de herencia sería mucho más seguro, o escribir métodos de serializar / deserializar en el método secundario le permitiría controlar la serialización / deserialización. Alternativamente, simplemente no usar serializar / deserializar y en su lugar usar su propia interfaz también puede ser más predecible que los métodos internos “mágicos”.