<?php
declare(strict_types=1);
final class Immutable {
private $data;
private $mutable = true;
public function __construct(array $args) {
if (false === $this->mutable) {
throw new \BadMethodCallException('Constructor called twice.');
}
$this->data = $this->sanitiseInput($args);
$this->mutable = false;
}
public function getData(): array {
return $this->data;
}
public function sanitiseInput(array $args): array {
return array_map(function($x) {
if (is_scalar($x)) return $x;
else if (is_object($x)) return $this->sanitiseObject($x);
else if (is_array($x)) return $this->sanitiseInput($x);
else throw new \InvalidArgumentException('Resources cannot be made immutable.');
}, $args);
}
private static function sanitiseObject(Immutable $object): Immutable {
return clone $object;
}
public function __clone() {
$this->data = $this->sanitiseInput($this->data);
}
public function __unset(string $id): void {}
public function __set(string $id, $val): void {}
}
$a = new Immutable([new stdClass, 10, 'yayaya']);
$b = new Immutable([1]);
var_dump($a);
var_dump($b);
Fatal error: Uncaught TypeError: Immutable::sanitiseObject(): Argument #1 ($object) must be of type Immutable, stdClass given, called in /in/p3o3m on line 22 and defined in /in/p3o3m:27
Stack trace:
#0 /in/p3o3m(22): Immutable::sanitiseObject(Object(stdClass))
#1 [internal function]: Immutable->{closure}(Object(stdClass))
#2 /in/p3o3m(20): array_map(Object(Closure), Array)
#3 /in/p3o3m(13): Immutable->sanitiseInput(Array)
#4 /in/p3o3m(37): Immutable->__construct(Array)
#5 {main}
thrown in /in/p3o3m on line 27
Process exited with code 255.
Output for 8.0.0 - 8.0.30, 8.1.0 - 8.1.28
Fatal error: Uncaught TypeError: Immutable::sanitiseObject(): Argument #1 ($object) must be of type Immutable, stdClass given, called in /in/p3o3m on line 22 and defined in /in/p3o3m:27
Stack trace:
#0 /in/p3o3m(22): Immutable::sanitiseObject(Object(stdClass))
#1 [internal function]: Immutable->{closure}(Object(stdClass))
#2 /in/p3o3m(25): array_map(Object(Closure), Array)
#3 /in/p3o3m(13): Immutable->sanitiseInput(Array)
#4 /in/p3o3m(37): Immutable->__construct(Array)
#5 {main}
thrown in /in/p3o3m on line 27
Process exited with code 255.
Fatal error: Uncaught TypeError: Argument 1 passed to Immutable::sanitiseObject() must be an instance of Immutable, instance of stdClass given, called in /in/p3o3m on line 22 and defined in /in/p3o3m:27
Stack trace:
#0 /in/p3o3m(22): Immutable::sanitiseObject(Object(stdClass))
#1 [internal function]: Immutable->{closure}(Object(stdClass))
#2 /in/p3o3m(25): array_map(Object(Closure), Array)
#3 /in/p3o3m(13): Immutable->sanitiseInput(Array)
#4 /in/p3o3m(37): Immutable->__construct(Array)
#5 {main}
thrown in /in/p3o3m on line 27
Process exited with code 255.