Skip to content

Commit 0c8e9d2

Browse files
committed
Readonly property can override get-only property declared in interface
1 parent 25b2525 commit 0c8e9d2

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

src/Rules/Properties/OverridingPropertyRule.php

+12-7
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,18 @@ public function processNode(Node $node, Scope $scope): array
7474
))->identifier('property.readWrite')->nonIgnorable()->build();
7575
}
7676
} elseif ($node->isReadOnly()) {
77-
$errors[] = RuleErrorBuilder::message(sprintf(
78-
'Readonly property %s::$%s overrides readwrite property %s::$%s.',
79-
$classReflection->getDisplayName(),
80-
$node->getName(),
81-
$prototype->getDeclaringClass()->getDisplayName(),
82-
$node->getName(),
83-
))->identifier('property.readOnly')->nonIgnorable()->build();
77+
if (
78+
!$this->phpVersion->supportsPropertyHooks()
79+
|| $prototype->isWritable()
80+
) {
81+
$errors[] = RuleErrorBuilder::message(sprintf(
82+
'Readonly property %s::$%s overrides readwrite property %s::$%s.',
83+
$classReflection->getDisplayName(),
84+
$node->getName(),
85+
$prototype->getDeclaringClass()->getDisplayName(),
86+
$node->getName(),
87+
))->identifier('property.readOnly')->nonIgnorable()->build();
88+
}
8489
}
8590

8691
if ($prototype->isPublic()) {

tests/PHPStan/Rules/Properties/OverridingPropertyRuleTest.php

+10
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,14 @@ public function testBug12466(): void
253253
]);
254254
}
255255

256+
public function testBug12586(): void
257+
{
258+
if (PHP_VERSION_ID < 80400) {
259+
$this->markTestSkipped('Test requires PHP 8.4.');
260+
}
261+
262+
$this->reportMaybes = true;
263+
$this->analyse([__DIR__ . '/data/bug-12586.php'], []);
264+
}
265+
256266
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php // lint >= 8.4
2+
3+
declare(strict_types=1);
4+
5+
namespace Bug12586;
6+
7+
interface Foo
8+
{
9+
public string $bar {
10+
get;
11+
}
12+
}
13+
14+
readonly class FooImpl implements Foo
15+
{
16+
public function __construct(
17+
public string $bar,
18+
)
19+
{
20+
}
21+
}

0 commit comments

Comments
 (0)