Skip to content

Commit 013940a

Browse files
committed
Prevent declaring hooked properties as readonly
1 parent 0b28f60 commit 013940a

File tree

4 files changed

+49
-0
lines changed

4 files changed

+49
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ lint:
8888
--exclude tests/PHPStan/Rules/Properties/data/non-abstract-hooked-properties-in-class.php \
8989
--exclude tests/PHPStan/Rules/Properties/data/hooked-properties-in-class.php \
9090
--exclude tests/PHPStan/Rules/Properties/data/hooked-properties-without-bodies-in-class.php \
91+
--exclude tests/PHPStan/Rules/Properties/data/readonly-property-hooks.php \
9192
--exclude tests/PHPStan/Rules/Classes/data/bug-12281.php \
9293
--exclude tests/PHPStan/Rules/Traits/data/bug-12281.php \
9394
--exclude tests/PHPStan/Rules/Classes/data/invalid-hooked-properties.php \

src/Rules/Properties/PropertyInClassRule.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@ public function processNode(Node $node, Scope $scope): array
7676
return [];
7777
}
7878

79+
if ($node->isReadOnly()) {
80+
if ($node->hasHooks()) {
81+
return [
82+
RuleErrorBuilder::message('Hooked properties cannot be readonly.')
83+
->nonIgnorable()
84+
->identifier('property.hookReadOnly')
85+
->build(),
86+
];
87+
}
88+
}
89+
7990
if (!$this->doAllHooksHaveBody($node)) {
8091
return [
8192
RuleErrorBuilder::message('Non-abstract properties cannot include hooks without bodies.')

tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,26 @@ public function testPhp84AndAbstractHookedPropertiesWithBodies(): void
151151
]);
152152
}
153153

154+
public function testPhp84AndReadonlyHookedProperties(): void
155+
{
156+
if (PHP_VERSION_ID < 80400) {
157+
$this->markTestSkipped('Test requires PHP 8.4 or later.');
158+
}
159+
160+
$this->analyse([__DIR__ . '/data/readonly-property-hooks.php'], [
161+
[
162+
'Hooked properties cannot be readonly.',
163+
7,
164+
],
165+
[
166+
'Hooked properties cannot be readonly.',
167+
12,
168+
],
169+
[
170+
'Hooked properties cannot be readonly.',
171+
14,
172+
],
173+
]);
174+
}
175+
154176
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ReadonlyPropertyHooks;
4+
5+
class HelloWorld
6+
{
7+
public readonly string $firstName {
8+
get => $this->firstName;
9+
set => $this->firstName;
10+
}
11+
12+
public readonly string $middleName { get => $this->middleName; }
13+
14+
public readonly string $lastName { set => $this->lastName; }
15+
}

0 commit comments

Comments
 (0)