Skip to content

Commit d108380

Browse files
authored
Fixed ReadOnly classes not interceptable
2 parents 359207a + 8b25283 commit d108380

File tree

7 files changed

+108
-12
lines changed

7 files changed

+108
-12
lines changed

src/Core/Transform/ProxiedClassModifier.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public function modify(): void
9999
{
100100
$this->convertToProxy();
101101
$this->unFinalMethods();
102+
$this->unReadOnlyClasses();
102103
$this->changeVisibility();
103104
$this->replaceSelfType();
104105
$this->replaceMagicConstants();
@@ -174,6 +175,15 @@ private function unFinalMethods(): void
174175
};
175176
}
176177

178+
private function unReadOnlyClasses(): void
179+
{
180+
$this->tokenCallbacks[] = function (Token $token) {
181+
if ($token->kind === TokenKind::ReadonlyKeyword) {
182+
$this->edit($token, '');
183+
}
184+
};
185+
}
186+
177187
/**
178188
* Change the visibility of the class members.
179189
*

src/Core/Transform/WovenClassBuilder.php

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -218,18 +218,9 @@ private function buildMethod(BetterReflectionMethod $refMethod): Method
218218

219219
$methodName = $refMethod->getName();
220220

221-
// ReadOnly Hack: https://github.com/nette/php-generator/issues/158
222-
foreach ($refMethod->getParameters() as $refParameter) {
223-
if ($refParameter->isPromoted()
224-
&& ($declaringClass = $refParameter->getDeclaringClass())
225-
&& ($refParameterName = $refParameter->getName())
226-
&& $declaringClass->hasProperty($refParameterName)
227-
&& ($property = $declaringClass->getProperty($refParameterName))
228-
&& $property->isReadOnly()
229-
) {
230-
/** @var PromotedParameter $parameter */
231-
$parameter = $method->getParameter($refParameterName);
232-
$parameter->setReadOnly();
221+
foreach ($method->getParameters() as $parameter) {
222+
if ($parameter instanceof PromotedParameter) {
223+
$parameter->setReadOnly(false);
233224
}
234225
}
235226

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
/** @noinspection PhpUnused */
3+
namespace Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly\Aspect;
4+
5+
use Okapi\Aop\Attributes\Around;
6+
use Okapi\Aop\Attributes\Aspect;
7+
8+
#[Aspect]
9+
class ReadonlyAspect
10+
{
11+
#[Around(
12+
class: 'Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly\Target\Readonly*',
13+
method: '*',
14+
)]
15+
public function doNothing(): void {}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly;
4+
5+
use Okapi\Aop\AopKernel;
6+
use Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly\Aspect\ReadonlyAspect;
7+
use Okapi\Aop\Tests\Util;
8+
9+
class Kernel extends AopKernel
10+
{
11+
protected ?string $cacheDir = Util::CACHE_DIR;
12+
13+
protected array $aspects = [
14+
ReadonlyAspect::class,
15+
];
16+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/** @noinspection PhpExpressionResultUnusedInspection */
3+
namespace Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly;
4+
5+
use Okapi\Aop\Tests\ClassLoaderMockTrait;
6+
use Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly\Target\ReadonlyClass;
7+
use Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly\Target\ReadonlyPromotedProperties;
8+
use Okapi\Aop\Tests\Util;
9+
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
10+
use PHPUnit\Framework\TestCase;
11+
12+
#[RunTestsInSeparateProcesses]
13+
class ReadonlyTest extends TestCase
14+
{
15+
use ClassLoaderMockTrait;
16+
17+
public function testReadonlyClass(): void
18+
{
19+
if (PHP_VERSION_ID < 80200) {
20+
$this->markTestSkipped('Readonly classes are supported only in PHP 8.2 and later.');
21+
}
22+
23+
Util::clearCache();
24+
Kernel::init();
25+
26+
$this->assertWillBeWoven(ReadonlyClass::class);
27+
28+
new ReadonlyClass();
29+
30+
$this->assertTrue(true);
31+
}
32+
33+
public function testReadonlyPromotedProperties(): void
34+
{
35+
Util::clearCache();
36+
Kernel::init();
37+
38+
$this->assertWillBeWoven(ReadonlyPromotedProperties::class);
39+
40+
new ReadonlyPromotedProperties('Walter Woshid', 42);
41+
42+
$this->assertTrue(true);
43+
}
44+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
/** @noinspection PhpLanguageLevelInspection Test will be skipped */
3+
namespace Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly\Target;
4+
5+
readonly class ReadonlyClass
6+
{
7+
public function ok(): void {}
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Okapi\Aop\Tests\Functional\AdviceBehavior\Readonly\Target;
4+
5+
class ReadonlyPromotedProperties
6+
{
7+
public function __construct(
8+
public readonly string $name,
9+
public readonly int $age,
10+
) {}
11+
}

0 commit comments

Comments
 (0)