diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index eb2ca18d..84923cd9 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -41,9 +41,11 @@
$this->storage[$key]
$this->storage[$key]
-
+
+ $flag
$ret
$ret
+ $v
Iterator
@@ -58,6 +60,14 @@
is_callable($function)
is_callable($function)
+
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+
@@ -158,6 +168,14 @@
$this->values
$this->values
+
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+
@@ -205,6 +223,9 @@
$this[$name]
+
+ ReturnTypeWillChange
+
@@ -223,6 +244,14 @@
(int) $priority
(int) $priority
+
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+
@@ -292,6 +321,10 @@
null !== $this->queue
+
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+
@@ -305,7 +338,6 @@
$data[]
$item
$item
- $item
@@ -314,6 +346,12 @@
$item
$item
+
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+
@@ -321,6 +359,12 @@
$item
$item
+
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+ ReturnTypeWillChange
+
@@ -377,9 +421,7 @@
-
- $length
- $this->getEncoding()
+
$this->getEncoding()
$this->getEncoding()
@@ -424,6 +466,12 @@
$ar['foo']['bar']
$ar['foo']['bar']
+
+ $unserialized
+
+
+ isImmutable
+
assertSame
@@ -500,6 +548,20 @@
$this->helper
+
+
+ $isImmutable
+
+
+ bool
+
+
+ $this->isImmutable
+
+
+ CustomArrayObject
+
+
'ErrorException'
diff --git a/src/ArrayObject.php b/src/ArrayObject.php
index 0e706db0..6cc195dd 100644
--- a/src/ArrayObject.php
+++ b/src/ArrayObject.php
@@ -12,6 +12,7 @@
use Serializable;
use UnexpectedValueException;
+use function array_key_exists;
use function array_keys;
use function asort;
use function class_exists;
@@ -92,7 +93,7 @@ public function __isset($key)
}
if (in_array($key, $this->protectedProperties)) {
- throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
+ throw new Exception\InvalidArgumentException("$key is a protected property, use a different key");
}
return isset($this->$key);
@@ -113,7 +114,7 @@ public function __set($key, $value)
}
if (in_array($key, $this->protectedProperties)) {
- throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
+ throw new Exception\InvalidArgumentException("$key is a protected property, use a different key");
}
$this->$key = $value;
@@ -133,7 +134,7 @@ public function __unset($key)
}
if (in_array($key, $this->protectedProperties)) {
- throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
+ throw new Exception\InvalidArgumentException("$key is a protected property, use a different key");
}
unset($this->$key);
@@ -154,7 +155,7 @@ public function &__get($key)
}
if (in_array($key, $this->protectedProperties, true)) {
- throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
+ throw new Exception\InvalidArgumentException("$key is a protected property, use a different key");
}
return $this->$key;
@@ -462,43 +463,43 @@ public function __unserialize($data)
{
$this->protectedProperties = array_keys(get_object_vars($this));
- foreach ($data as $k => $v) {
- switch ($k) {
- case 'flag':
- $this->setFlags((int) $v);
- break;
-
- case 'storage':
- if (! is_array($v) && ! is_object($v)) {
- throw new UnexpectedValueException(sprintf(
- 'Cannot deserialize %s instance: corrupt storage data;'
- . ' expected array or object, received %s',
- self::class,
- gettype($v)
- ));
- }
-
- $this->exchangeArray($v);
- break;
-
- case 'iteratorClass':
- if (! is_string($v)) {
- throw new UnexpectedValueException(sprintf(
- 'Cannot deserialize %s instance: invalid iteratorClass; expected string, received %s',
- self::class,
- is_object($v) ? get_class($v) : gettype($v)
- ));
- }
-
- $this->setIteratorClass($v);
- break;
-
- case 'protectedProperties':
- break;
-
- default:
- $this->__set($k, $v);
+ // Unserialize protected internal properties first
+ if (array_key_exists('flag', $data)) {
+ $this->setFlags((int) $data['flag']);
+ unset($data['flag']);
+ }
+
+ if (array_key_exists('storage', $data)) {
+ if (! is_array($data['storage']) && ! is_object($data['storage'])) {
+ throw new UnexpectedValueException(sprintf(
+ 'Cannot deserialize %s instance: corrupt storage data; expected array or object, received %s',
+ self::class,
+ gettype($data['storage'])
+ ));
+ }
+ $this->exchangeArray($data['storage']);
+ unset($data['storage']);
+ }
+
+ if (array_key_exists('iteratorClass', $data)) {
+ if (! is_string($data['iteratorClass'])) {
+ throw new UnexpectedValueException(sprintf(
+ 'Cannot deserialize %s instance: invalid iteratorClass; expected string, received %s',
+ self::class,
+ is_object($data['iteratorClass'])
+ ? get_class($data['iteratorClass'])
+ : gettype($data['iteratorClass'])
+ ));
}
+ $this->setIteratorClass($data['iteratorClass']);
+ unset($data['iteratorClass']);
+ }
+
+ unset($data['protectedProperties']);
+
+ // Unserialize array keys after resolving protected properties to ensure configuration is used.
+ foreach ($data as $k => $v) {
+ $this->__set($k, $v);
}
}
}
diff --git a/test/ArrayObjectTest.php b/test/ArrayObjectTest.php
index 0f626847..9cf8cf73 100644
--- a/test/ArrayObjectTest.php
+++ b/test/ArrayObjectTest.php
@@ -401,4 +401,15 @@ public function testSerializationRestoresProperties(): void
self::assertEquals($ar, unserialize(serialize($ar)));
}
+
+ public function testSerializationRestoresProtectedProperties(): void
+ {
+ $ar = new CustomArrayObject([], ArrayObject::ARRAY_AS_PROPS);
+ self::assertTrue($ar->isImmutable());
+
+ $serialized = serialize($ar);
+ $unserialized = unserialize($serialized);
+
+ self::assertTrue($unserialized->isImmutable());
+ }
}
diff --git a/test/CustomArrayObject.php b/test/CustomArrayObject.php
new file mode 100644
index 00000000..40586be4
--- /dev/null
+++ b/test/CustomArrayObject.php
@@ -0,0 +1,18 @@
+isImmutable;
+ }
+}