Hey Máté, On Tue, 15 Nov 2022 at 07:30, Máté Kocsis <kocsismat...@gmail.com> wrote:
> Hi Everyone, > > Following Nicolas' thread about "Issues with readonly classes" ( > https://externals.io/message/118554), we created an RFC to fix two issues > with the readonly behavior: https://wiki.php.net/rfc/readonly_amendments > > Since I was reviewing https://github.com/lcobucci/jwt/pull/979 today, I had to put the "why immutability is an LSP requirement" in examples. As explained in https://github.com/lcobucci/jwt/pull/979#discussion_r1025280053, a consumer relying on a `readonly` implementation of a class probably also expects replacement implementations as read-only. I am aware that we lack the `readonly` marker at interface level (would be really neat), but the practical example is as follows: ```php <?php /* readonly */ class ImmutableCounter { public function __construct(private readonly int $count) {} public function add1(): self { return new self($this->count + 1); } public function value(): int { return $this->count; } } // assuming the proposed RFC is in place, this is now possible: class MutableCounter extends ImmutableCounter { public function __construct(private int $count) {} public function add1(): self { return new self(++$this->count); } public function value(): int { return $this->count; } } $counter1 = new ImmutableCounter(0); $counter2 = $counter1->add1(); $counter3 = $counter2->add1(); var_dump([$counter1->value(), $counter2->value(), $counter3->value()]); $mutableCounter1 = new MutableCounter(0); $mutableCounter2 = $mutableCounter1->add1(); $mutableCounter3 = $mutableCounter2->add1(); var_dump([$mutableCounter1->value(), $mutableCounter2->value(), $mutableCounter3->value()]); ``` This prints ( https://3v4l.org/IDhRY ) ``` array(4) { [0]=> int(0) [1]=> int(1) [2]=> int(2) } array(4) { [0]=> int(1) [1]=> int(2) [2]=> int(2) } ``` I took a simplified example on purpose, just to demonstrate the problem with `readonly` disappearing in child classes. That's really really confusing, buggy, and, from a consumer PoV, broken (LSP violation too, transitively). That said, allowing mutation in `__clone()` is fine. Marco Pivetta https://twitter.com/Ocramius https://ocramius.github.io/