Skip to content

Commit d3c6b62

Browse files
committed
Property tag @property-read with private property keeps the property non-writable
1 parent c7d4124 commit d3c6b62

File tree

5 files changed

+54
-3
lines changed

5 files changed

+54
-3
lines changed

src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ private function findClassReflectionWithProperty(
4747
$isWritable = $propertyTags[$propertyName]->isWritable();
4848
if ($classReflection->hasNativeProperty($propertyName)) {
4949
$nativeProperty = $classReflection->getNativeProperty($propertyName);
50-
$isReadable = $isReadable || $nativeProperty->isReadable();
51-
$isWritable = $isWritable || $nativeProperty->isWritable();
50+
if (!$nativeProperty->isPrivate() && !$nativeProperty->isStatic()) {
51+
$isReadable = $isReadable || $nativeProperty->isReadable();
52+
$isWritable = $isWritable || $nativeProperty->isWritable();
53+
}
5254
}
5355

5456
return new AnnotationPropertyReflection(

src/Reflection/Php/PhpClassReflectionExtension.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ private function createProperty(
216216
$types[] = $value;
217217
}
218218

219-
return new PhpPropertyReflection($declaringClassReflection, null, null, TypeCombinator::union(...$types), $classReflection->getNativeReflection()->getProperty($propertyName), null, null, null, false, false, false, false, [], false);
219+
return new PhpPropertyReflection($declaringClassReflection, null, null, TypeCombinator::union(...$types), $classReflection->getNativeReflection()->getProperty($propertyName), null, null, null, false, false, false, false, [], false, true, false);
220220
}
221221
}
222222

@@ -433,6 +433,8 @@ private function createProperty(
433433
$isAllowedPrivateMutation,
434434
$this->attributeReflectionFactory->fromNativeReflection($propertyReflection->getAttributes(), InitializerExprContext::fromClass($declaringClassReflection->getName(), $declaringClassReflection->getFileName())),
435435
$isFinal,
436+
$annotationProperty->isReadable(),
437+
$annotationProperty->isWritable(),
436438
);
437439
}
438440
}
@@ -452,6 +454,8 @@ private function createProperty(
452454
$isAllowedPrivateMutation,
453455
$this->attributeReflectionFactory->fromNativeReflection($propertyReflection->getAttributes(), InitializerExprContext::fromClass($declaringClassReflection->getName(), $declaringClassReflection->getFileName())),
454456
$isFinal,
457+
true,
458+
true,
455459
);
456460
}
457461

src/Reflection/Php/PhpPropertyReflection.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ public function __construct(
4545
private bool $isAllowedPrivateMutation,
4646
private array $attributes,
4747
private bool $isFinal,
48+
private bool $readable,
49+
private bool $writable,
4850
)
4951
{
5052
}
@@ -176,6 +178,10 @@ public function getNativeType(): Type
176178

177179
public function isReadable(): bool
178180
{
181+
if (!$this->readable) {
182+
return false;
183+
}
184+
179185
if ($this->isStatic()) {
180186
return true;
181187
}
@@ -189,6 +195,10 @@ public function isReadable(): bool
189195

190196
public function isWritable(): bool
191197
{
198+
if (!$this->writable) {
199+
return false;
200+
}
201+
192202
if ($this->isStatic()) {
193203
return true;
194204
}

tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,15 @@ public function testBug12553(): void
111111
$this->analyse([__DIR__ . '/../Variables/data/bug-12553.php'], []);
112112
}
113113

114+
public function testPrivatePropertyTagRead(): void
115+
{
116+
$this->checkThisOnly = false;
117+
$this->analyse([__DIR__ . '/data/private-property-tag-read.php'], [
118+
[
119+
'Property PrivatePropertyTagRead\Foo::$foo is not writable.',
120+
22,
121+
],
122+
]);
123+
}
124+
114125
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace PrivatePropertyTagRead;
4+
5+
use AllowDynamicProperties;
6+
7+
/**
8+
* @property-read int $foo
9+
* @property-read int $bar
10+
*/
11+
#[AllowDynamicProperties]
12+
class Foo
13+
{
14+
15+
private int $foo;
16+
17+
public int $bar;
18+
19+
}
20+
21+
function (Foo $foo): void {
22+
$foo->foo = 1;
23+
$foo->bar = 2;
24+
};

0 commit comments

Comments
 (0)