Skip to content

Commit 70f2ad1

Browse files
authored
Merge pull request #667 from phpDocumentor/feature/property-hooks
Centralize property creation.
2 parents a0f93c6 + fd8f4a3 commit 70f2ad1

18 files changed

+696
-142
lines changed

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ fix-code-style:
1212

1313
.PHONY: static-code-analysis
1414
static-code-analysis: vendor ## Runs a static code analysis with phpstan/phpstan and vimeo/psalm
15-
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.1-cli vendor/bin/phpstan --configuration=phpstan.neon
16-
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.1-cli vendor/bin/psalm.phar
15+
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.2-cli vendor/bin/phpstan --configuration=phpstan.neon
16+
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.2-cli vendor/bin/psalm.phar
1717

1818
.PHONY: test
1919
test: test-unit test-functional ## Runs all test suites with phpunit/phpunit
@@ -25,7 +25,7 @@ test-unit: ## Runs unit tests with phpunit/phpunit
2525

2626
.PHONY: test-functional
2727
test-functional: ## Runs unit tests with phpunit/phpunit
28-
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.1-cli vendor/bin/phpunit --testsuite=functional
28+
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.1-cli vendor/bin/phpunit --testsuite=integration
2929

3030
.PHONY: dependency-analysis
3131
dependency-analysis: vendor ## Runs a dependency analysis with maglnet/composer-require-checker

src/phpDocumentor/Reflection/Php/Factory/AbstractFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ abstract class AbstractFactory implements ProjectFactoryStrategy
3030
{
3131
/** @param iterable<Reducer> $reducers */
3232
public function __construct(
33-
private readonly DocBlockFactoryInterface $docBlockFactory,
33+
protected readonly DocBlockFactoryInterface $docBlockFactory,
3434
protected readonly iterable $reducers = [],
3535
) {
3636
}

src/phpDocumentor/Reflection/Php/Factory/ConstructorPromotion.php

Lines changed: 16 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@
88
use phpDocumentor\Reflection\DocBlockFactoryInterface;
99
use phpDocumentor\Reflection\Fqsen;
1010
use phpDocumentor\Reflection\Location;
11-
use phpDocumentor\Reflection\Php\AsyncVisibility;
1211
use phpDocumentor\Reflection\Php\Class_ as ClassElement;
1312
use phpDocumentor\Reflection\Php\Factory\Reducer\Reducer;
1413
use phpDocumentor\Reflection\Php\ProjectFactoryStrategy;
15-
use phpDocumentor\Reflection\Php\Property;
1614
use phpDocumentor\Reflection\Php\StrategyContainer;
17-
use phpDocumentor\Reflection\Php\Visibility;
1815
use PhpParser\Modifiers;
1916
use PhpParser\Node\Expr\Variable;
2017
use PhpParser\Node\Param;
@@ -67,17 +64,22 @@ private function promoteParameterToProperty(ContextStack $context, StrategyConta
6764
Assert::isInstanceOf($methodContainer, ClassElement::class);
6865
Assert::isInstanceOf($param->var, Variable::class);
6966

70-
$property = new Property(
71-
new Fqsen($methodContainer->getFqsen() . '::$' . (string) $param->var->name),
72-
$this->buildPropertyVisibilty($param->flags),
73-
$this->createDocBlock($param->getDocComment(), $context->getTypeContext()),
74-
$param->default !== null ? $this->valueConverter->prettyPrintExpr($param->default) : null,
75-
false,
76-
new Location($param->getLine()),
77-
new Location($param->getEndLine()),
78-
(new Type())->fromPhpParser($param->type),
79-
$this->readOnly($param->flags),
80-
);
67+
$property = PropertyBuilder::create(
68+
$this->valueConverter,
69+
$this->docBlockFactory,
70+
$strategies,
71+
$this->reducers,
72+
)->fqsen(new Fqsen($methodContainer->getFqsen() . '::$' . (string) $param->var->name))
73+
->visibility($param)
74+
->type($param->type)
75+
->docblock($param->getDocComment())
76+
->default($param->default)
77+
->readOnly($this->readOnly($param->flags))
78+
->static(false)
79+
->startLocation(new Location($param->getLine(), $param->getStartFilePos()))
80+
->endLocation(new Location($param->getEndLine(), $param->getEndFilePos()))
81+
->hooks($param->hooks ?? [])
82+
->build($context);
8183

8284
foreach ($this->reducers as $reducer) {
8385
$property = $reducer->reduce($context, $param, $strategies, $property);
@@ -90,44 +92,6 @@ private function promoteParameterToProperty(ContextStack $context, StrategyConta
9092
$methodContainer->addProperty($property);
9193
}
9294

93-
private function buildPropertyVisibilty(int $flags): Visibility
94-
{
95-
if ((bool) ($flags & Modifiers::VISIBILITY_SET_MASK) !== false) {
96-
return new AsyncVisibility(
97-
$this->buildReadVisibility($flags),
98-
$this->buildWriteVisibility($flags),
99-
);
100-
}
101-
102-
return $this->buildReadVisibility($flags);
103-
}
104-
105-
private function buildReadVisibility(int $flags): Visibility
106-
{
107-
if ((bool) ($flags & Modifiers::PRIVATE) === true) {
108-
return new Visibility(Visibility::PRIVATE_);
109-
}
110-
111-
if ((bool) ($flags & Modifiers::PROTECTED) === true) {
112-
return new Visibility(Visibility::PROTECTED_);
113-
}
114-
115-
return new Visibility(Visibility::PUBLIC_);
116-
}
117-
118-
private function buildWriteVisibility(int $flags): Visibility
119-
{
120-
if ((bool) ($flags & Modifiers::PRIVATE_SET) === true) {
121-
return new Visibility(Visibility::PRIVATE_);
122-
}
123-
124-
if ((bool) ($flags & Modifiers::PROTECTED_SET) === true) {
125-
return new Visibility(Visibility::PROTECTED_);
126-
}
127-
128-
return new Visibility(Visibility::PUBLIC_);
129-
}
130-
13195
private function readOnly(int $flags): bool
13296
{
13397
return (bool) ($flags & Modifiers::READONLY) === true;

src/phpDocumentor/Reflection/Php/Factory/ContextStack.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,22 @@
88
use phpDocumentor\Reflection\Element;
99
use phpDocumentor\Reflection\Php\File as FileElement;
1010
use phpDocumentor\Reflection\Php\Project;
11+
use phpDocumentor\Reflection\Php\PropertyHook;
1112
use phpDocumentor\Reflection\Types\Context as TypeContext;
1213

1314
use function array_reverse;
1415
use function end;
1516

1617
final class ContextStack
1718
{
18-
/** @var (Element|FileElement)[] */
19+
/** @var (Element|FileElement|PropertyHook)[] */
1920
private array $elements = [];
2021

2122
public function __construct(private readonly Project $project, private readonly TypeContext|null $typeContext = null)
2223
{
2324
}
2425

25-
/** @param (Element|FileElement)[] $elements */
26+
/** @param (Element|FileElement|PropertyHook)[] $elements */
2627
private static function createFromSelf(Project $project, TypeContext|null $typeContext, array $elements): self
2728
{
2829
$self = new self($project, $typeContext);
@@ -31,7 +32,7 @@ private static function createFromSelf(Project $project, TypeContext|null $typeC
3132
return $self;
3233
}
3334

34-
public function push(Element|FileElement $element): self
35+
public function push(Element|FileElement|PropertyHook $element): self
3536
{
3637
$elements = $this->elements;
3738
$elements[] = $element;
@@ -54,7 +55,7 @@ public function getProject(): Project
5455
return $this->project;
5556
}
5657

57-
public function peek(): Element|FileElement
58+
public function peek(): Element|FileElement|PropertyHook
5859
{
5960
$element = end($this->elements);
6061
if ($element === false) {
@@ -72,7 +73,7 @@ public function peek(): Element|FileElement
7273
*
7374
* @param class-string $type
7475
*/
75-
public function search(string $type): Element|FileElement|null
76+
public function search(string $type): Element|FileElement|PropertyHook|null
7677
{
7778
$reverseElements = array_reverse($this->elements);
7879
foreach ($reverseElements as $element) {

src/phpDocumentor/Reflection/Php/Factory/Property.php

Lines changed: 17 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@
1515

1616
use phpDocumentor\Reflection\DocBlockFactoryInterface;
1717
use phpDocumentor\Reflection\Location;
18-
use phpDocumentor\Reflection\Php\AsyncVisibility;
1918
use phpDocumentor\Reflection\Php\Class_;
2019
use phpDocumentor\Reflection\Php\Factory\Reducer\Reducer;
2120
use phpDocumentor\Reflection\Php\Property as PropertyDescriptor;
2221
use phpDocumentor\Reflection\Php\StrategyContainer;
2322
use phpDocumentor\Reflection\Php\Trait_;
24-
use phpDocumentor\Reflection\Php\Visibility;
2523
use PhpParser\Node\Stmt\Property as PropertyNode;
2624
use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
2725
use Webmozart\Assert\Assert;
@@ -73,22 +71,23 @@ protected function doCreate(
7371

7472
$iterator = new PropertyIterator($object);
7573
foreach ($iterator as $stmt) {
76-
$default = $iterator->getDefault();
77-
if ($default !== null) {
78-
$default = $this->valueConverter->prettyPrintExpr($default);
79-
}
80-
81-
$property = new PropertyDescriptor(
82-
$stmt->getFqsen(),
83-
$this->buildVisibility($stmt),
84-
$this->createDocBlock($stmt->getDocComment(), $context->getTypeContext()),
85-
$default,
86-
$stmt->isStatic(),
87-
new Location($stmt->getLine()),
88-
new Location($stmt->getEndLine()),
89-
(new Type())->fromPhpParser($stmt->getType()),
90-
$stmt->isReadonly(),
91-
);
74+
$property = PropertyBuilder::create(
75+
$this->valueConverter,
76+
$this->docBlockFactory,
77+
$strategies,
78+
$this->reducers,
79+
)
80+
->fqsen($stmt->getFqsen())
81+
->visibility($stmt)
82+
->type($stmt->getType())
83+
->docblock($stmt->getDocComment())
84+
->default($iterator->getDefault())
85+
->static($stmt->isStatic())
86+
->startLocation(new Location($stmt->getLine()))
87+
->endLocation(new Location($stmt->getEndLine()))
88+
->readOnly($stmt->isReadonly())
89+
->hooks($stmt->getHooks())
90+
->build($context);
9291

9392
foreach ($this->reducers as $reducer) {
9493
$property = $reducer->reduce($context, $object, $strategies, $property);
@@ -103,48 +102,4 @@ protected function doCreate(
103102

104103
return null;
105104
}
106-
107-
/**
108-
* Converts the visibility of the property to a valid Visibility object.
109-
*/
110-
private function buildVisibility(PropertyIterator $node): Visibility
111-
{
112-
if ($node->isAsync() === false) {
113-
return $this->buildReadVisibility($node);
114-
}
115-
116-
$readVisibility = $this->buildReadVisibility($node);
117-
$writeVisibility = $this->buildWriteVisibility($node);
118-
119-
return new AsyncVisibility(
120-
$readVisibility,
121-
$writeVisibility,
122-
);
123-
}
124-
125-
private function buildReadVisibility(PropertyIterator $node): Visibility
126-
{
127-
if ($node->isPrivate()) {
128-
return new Visibility(Visibility::PRIVATE_);
129-
}
130-
131-
if ($node->isProtected()) {
132-
return new Visibility(Visibility::PROTECTED_);
133-
}
134-
135-
return new Visibility(Visibility::PUBLIC_);
136-
}
137-
138-
private function buildWriteVisibility(PropertyIterator $node): Visibility
139-
{
140-
if ($node->isPrivateSet()) {
141-
return new Visibility(Visibility::PRIVATE_);
142-
}
143-
144-
if ($node->isProtectedSet()) {
145-
return new Visibility(Visibility::PROTECTED_);
146-
}
147-
148-
return new Visibility(Visibility::PUBLIC_);
149-
}
150105
}

0 commit comments

Comments
 (0)