Skip to content

Commit bf85e9d

Browse files
herndlmondrejmirtes
authored andcommittedNov 6, 2024·
Support @readonly PHPDoc on the class as alternative to @immutable
1 parent e3ee899 commit bf85e9d

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed
 

‎src/Reflection/ClassReflection.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,7 @@ public function isImmutable(): bool
12381238
{
12391239
if ($this->isImmutable === null) {
12401240
$resolvedPhpDoc = $this->getResolvedPhpDoc();
1241-
$this->isImmutable = $resolvedPhpDoc !== null && $resolvedPhpDoc->isImmutable();
1241+
$this->isImmutable = $resolvedPhpDoc !== null && ($resolvedPhpDoc->isImmutable() || $resolvedPhpDoc->isReadOnly());
12421242

12431243
$parentClass = $this->getParentClass();
12441244
if ($parentClass !== null && !$this->isImmutable) {

‎tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php

+18
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,22 @@ public function testFeature7648(): void
160160
$this->analyse([__DIR__ . '/data/feature-7648.php'], []);
161161
}
162162

163+
public function testFeature11775(): void
164+
{
165+
if (PHP_VERSION_ID < 70400) {
166+
$this->markTestSkipped('Test requires PHP 7.4.');
167+
}
168+
169+
$this->analyse([__DIR__ . '/data/feature-11775.php'], [
170+
[
171+
'@readonly property Feature11775\FooImmutable::$i is assigned outside of the constructor.',
172+
22,
173+
],
174+
[
175+
'@readonly property Feature11775\FooReadonly::$i is assigned outside of the constructor.',
176+
43,
177+
],
178+
]);
179+
}
180+
163181
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php declare(strict_types = 1); // lint >= 7.4
2+
3+
namespace Feature11775;
4+
5+
/** @immutable */
6+
class FooImmutable
7+
{
8+
private int $i;
9+
10+
public function __construct(int $i)
11+
{
12+
$this->i = $i;
13+
}
14+
15+
public function getId(): int
16+
{
17+
return $this->i;
18+
}
19+
20+
public function setId(): void
21+
{
22+
$this->i = 5;
23+
}
24+
}
25+
26+
/** @readonly */
27+
class FooReadonly
28+
{
29+
private int $i;
30+
31+
public function __construct(int $i)
32+
{
33+
$this->i = $i;
34+
}
35+
36+
public function getId(): int
37+
{
38+
return $this->i;
39+
}
40+
41+
public function setId(): void
42+
{
43+
$this->i = 5;
44+
}
45+
}

0 commit comments

Comments
 (0)
Please sign in to comment.