Skip to content

Commit d629cd4

Browse files
committed
Collect dependencies defined in property hooks
Add support for collecting dependencies from PHP 8.4 property hooks: - Handle typed parameters in set hooks (e.g., set(MyClass $value)) - Dependencies from expressions within hook bodies (new, static calls, etc.) are already collected by the AST traverser Fixes #515
1 parent d7e3f5b commit d629cd4

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

src/Analyzer/FileVisitor.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ public function enterNode(Node $node): void
6767

6868
// handles attribute definition like #[MyAttribute]
6969
$this->handleAttributeNode($node);
70+
71+
// handles property hooks like public string $name { get => ...; set { ... } }
72+
$this->handlePropertyHookNode($node);
7073
}
7174

7275
public function getClassDescriptions(): array
@@ -349,4 +352,16 @@ private function addParamDependency(Node\Param $node): void
349352
$this->classDescriptionBuilder
350353
->addDependency(new ClassDependency($type->toString(), $node->getLine()));
351354
}
355+
356+
private function handlePropertyHookNode(Node $node): void
357+
{
358+
if (!($node instanceof Node\PropertyHook)) {
359+
return;
360+
}
361+
362+
// Handle parameters in set hooks (e.g., set(MyClass $value) { ... })
363+
foreach ($node->params as $param) {
364+
$this->addParamDependency($param);
365+
}
366+
}
352367
}

tests/Unit/Analyzer/FileParser/CanParsePropertyHooksTest.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,75 @@ public function __construct(string $firstName, string $lastName) {
4040

4141
self::assertInstanceOf(ClassDescription::class, $cd[0]);
4242
}
43+
44+
public function test_it_collects_dependencies_from_property_hooks(): void
45+
{
46+
$code = <<< 'EOF'
47+
<?php
48+
namespace App\Foo;
49+
50+
use App\Services\Formatter;
51+
use App\Services\Validator;
52+
use App\Services\Logger;
53+
54+
class User {
55+
public string $name {
56+
get {
57+
$formatter = new Formatter();
58+
return $formatter->format($this->name);
59+
}
60+
set {
61+
$validator = new Validator();
62+
$validator->validate($value);
63+
$this->name = $value;
64+
Logger::log('Name set');
65+
}
66+
}
67+
}
68+
EOF;
69+
70+
$fp = FileParserFactory::forPhpVersion(TargetPhpVersion::PHP_8_4);
71+
$fp->parse($code, 'relativePathName');
72+
73+
$cd = $fp->getClassDescriptions();
74+
75+
self::assertInstanceOf(ClassDescription::class, $cd[0]);
76+
77+
$dependencies = $cd[0]->getDependencies();
78+
$dependencyNames = array_map(fn ($dep) => $dep->getFQCN()->toString(), $dependencies);
79+
80+
self::assertContains('App\Services\Formatter', $dependencyNames);
81+
self::assertContains('App\Services\Validator', $dependencyNames);
82+
self::assertContains('App\Services\Logger', $dependencyNames);
83+
}
84+
85+
public function test_it_collects_dependencies_from_property_hook_parameters(): void
86+
{
87+
$code = <<< 'EOF'
88+
<?php
89+
namespace App\Foo;
90+
91+
use App\ValueObjects\Name;
92+
93+
class User {
94+
public string $name {
95+
set (Name $name) {
96+
$this->name = $name->toString();
97+
}
98+
}
99+
}
100+
EOF;
101+
102+
$fp = FileParserFactory::forPhpVersion(TargetPhpVersion::PHP_8_4);
103+
$fp->parse($code, 'relativePathName');
104+
105+
$cd = $fp->getClassDescriptions();
106+
107+
self::assertInstanceOf(ClassDescription::class, $cd[0]);
108+
109+
$dependencies = $cd[0]->getDependencies();
110+
$dependencyNames = array_map(fn ($dep) => $dep->getFQCN()->toString(), $dependencies);
111+
112+
self::assertContains('App\ValueObjects\Name', $dependencyNames);
113+
}
43114
}

0 commit comments

Comments
 (0)