Skip to content

Commit d539515

Browse files
code style: Order class elements in methods and properties. (#62)
1 parent 0fb6d3b commit d539515

15 files changed

+326
-303
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## 0.3.1 Under development
44

5+
- Bug #62: Order class elements in methods and properties (@terabytesoftw)
6+
57
## 0.3.0 June 27, 2025
68

79
- Enh #35: Move config fixtures into `config` subdirectory (@terabytesoftw)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<p align="center">
22
<a href="https://github.com/yii2-extensions/phpstan" target="_blank">
3-
<img src="https://www.yiiframework.com/image/yii_logo_light.svg" height="100px;" alt="Yii Framework">
3+
<img src="https://www.yiiframework.com/image/yii_logo_light.svg" alt="Yii Framework">
44
</a>
55
<h1 align="center">Extension for PHPStan</h1>
66
</p>

docs/installation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ vendor/bin/phpstan --version
253253

254254
## Next steps
255255

256-
Once installation is complete:
256+
Once the installation is complete.
257257

258258
- ⚙️ [Configuration Reference](configuration.md)
259259
- 💡 [Usage Examples](examples.md)

docs/testing.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
This package uses [composer-require-checker](https://github.com/maglnet/ComposerRequireChecker) to check if all dependencies are correctly defined in `composer.json`.
66

7-
To run the checker, execute the following command:
7+
To run the checker, execute the following command.
88

99
```shell
1010
composer run check-dependencies
@@ -13,23 +13,23 @@ composer run check-dependencies
1313
## Easy coding standard
1414

1515
The code is checked with [Easy Coding Standard](https://github.com/easy-coding-standard/easy-coding-standard) and
16-
[PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer). To run it:
16+
[PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer). To run it.
1717

1818
```shell
1919
composer run ecs
2020
```
2121

2222
## Static analysis
2323

24-
The code is statically analyzed with [PHPStan](https://phpstan.org/). To run static analysis:
24+
The code is statically analyzed with [PHPStan](https://phpstan.org/). To run static analysis.
2525

2626
```shell
27-
composer run phpstan
27+
composer run static
2828
```
2929

3030
## Unit tests
3131

32-
The code is tested with [PHPUnit](https://phpunit.de/). To run tests:
32+
The code is tested with [PHPUnit](https://phpunit.de/). To run tests.
3333

3434
```
3535
composer run test

ecs.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,28 @@
1818
'space_before_parenthesis' => true,
1919
],
2020
)
21+
->withConfiguredRule(
22+
OrderedClassElementsFixer::class,
23+
[
24+
'order' => [
25+
'use_trait',
26+
'constant_public',
27+
'constant_protected',
28+
'constant_private',
29+
'property_public',
30+
'property_protected',
31+
'property_private',
32+
'construct',
33+
'destruct',
34+
'magic',
35+
'phpunit',
36+
'method_public',
37+
'method_protected',
38+
'method_private',
39+
],
40+
'sort_algorithm' => 'alpha',
41+
],
42+
)
2143
->withConfiguredRule(
2244
OrderedImportsFixer::class,
2345
[
@@ -49,7 +71,6 @@
4971
->withRules(
5072
[
5173
NoUnusedImportsFixer::class,
52-
OrderedClassElementsFixer::class,
5374
OrderedTraitsFixer::class,
5475
SingleQuoteFixer::class,
5576
]

src/ServiceMap.php

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,18 @@ final class ServiceMap
7878
private array $behaviors = [];
7979

8080
/**
81-
* Component definitions map for Yii Application analysis.
81+
* Reverse index mapping class names to component IDs for optimized lookups.
8282
*
83-
* @phpstan-var string[]
83+
* @phpstan-var array<string, string>
8484
*/
85-
private array $components = [];
85+
private array $componentClassToIdMap = [];
8686

8787
/**
88-
* Reverse index mapping class names to component IDs for optimized lookups.
88+
* Component definitions map for Yii Application analysis.
8989
*
90-
* @phpstan-var array<string, string>
90+
* @phpstan-var string[]
9191
*/
92-
private array $componentClassToIdMap = [];
92+
private array $components = [];
9393

9494
/**
9595
* Component definitions for Yii Application analysis.
@@ -189,29 +189,6 @@ public function getComponentClassById(string $id): string|null
189189
return $this->components[$id] ?? null;
190190
}
191191

192-
/**
193-
* Retrieves the component definition array by its identifier.
194-
*
195-
* Looks up the component definition registered under the specified component ID in the internal component
196-
* definitions map.
197-
*
198-
* This method provides access to the raw component configuration array, enabling static analysis tools and IDEs to
199-
* inspect component properties, dependencies, and configuration options for accurate type inference and reflection
200-
* analysis.
201-
*
202-
* @param string $id Component identifier to look up in the component definitions map.
203-
*
204-
* @return array Component definition array with configuration options, or empty array if not found.
205-
*
206-
* @phpstan-return array<array-key, mixed>
207-
*/
208-
public function getComponentDefinitionById(string $id): array
209-
{
210-
$definition = $this->componentsDefinitions[$id] ?? null;
211-
212-
return is_array($definition) ? $definition : [];
213-
}
214-
215192
/**
216193
* Retrieves the component definition array for a given class name.
217194
*
@@ -238,6 +215,29 @@ public function getComponentDefinitionByClassName(string $class): array|null
238215
return $this->getComponentDefinitionById($id);
239216
}
240217

218+
/**
219+
* Retrieves the component definition array by its identifier.
220+
*
221+
* Looks up the component definition registered under the specified component ID in the internal component
222+
* definitions map.
223+
*
224+
* This method provides access to the raw component configuration array, enabling static analysis tools and IDEs to
225+
* inspect component properties, dependencies, and configuration options for accurate type inference and reflection
226+
* analysis.
227+
*
228+
* @param string $id Component identifier to look up in the component definitions map.
229+
*
230+
* @return array Component definition array with configuration options, or empty array if not found.
231+
*
232+
* @phpstan-return array<array-key, mixed>
233+
*/
234+
public function getComponentDefinitionById(string $id): array
235+
{
236+
$definition = $this->componentsDefinitions[$id] ?? null;
237+
238+
return is_array($definition) ? $definition : [];
239+
}
240+
241241
/**
242242
* Retrieves the fully qualified class name of a Yii Service by its identifier.
243243
*

src/type/ActiveRecordDynamicStaticMethodReturnTypeExtension.php

Lines changed: 82 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -75,74 +75,6 @@ public function getClass(): string
7575
return ActiveRecord::class;
7676
}
7777

78-
/**
79-
* Determines whether the specified static method is supported for dynamic return type inference.
80-
*
81-
* Inspects the method's return type and class context to decide if the static method should be handled by this
82-
* extension for dynamic return type analysis.
83-
*
84-
* This includes methods returning `$this`, union types containing {@see ActiveRecord} subclasses, or types related
85-
* to {@see ActiveQuery}.
86-
*
87-
* This method enables PHPStan to apply custom type inference for static {@see ActiveRecord} query methods ensuring
88-
* accurate autocompletion and static analysis for methods such as {@see ActiveRecord::findOne()},
89-
* {@see ActiveRecord::findAll()}, and custom query builders.
90-
*
91-
* @param MethodReflection $methodReflection Reflection instance for the method being analyzed.
92-
*
93-
* @return bool `true` if the static method is supported for dynamic return type inference; `false` otherwise.
94-
*/
95-
public function isStaticMethodSupported(MethodReflection $methodReflection): bool
96-
{
97-
$variants = $methodReflection->getVariants();
98-
99-
if (count($variants) === 0) {
100-
return false;
101-
}
102-
103-
$returnType = $variants[0]->getReturnType();
104-
105-
if ($returnType::class === ThisType::class) {
106-
return true;
107-
}
108-
109-
if ($returnType::class === UnionType::class) {
110-
foreach ($returnType->getTypes() as $type) {
111-
$classNames = $type->getObjectClassNames();
112-
113-
if (count($classNames) > 0) {
114-
$className = $classNames[0];
115-
116-
if ($this->reflectionProvider->hasClass($className)) {
117-
$classReflection = $this->reflectionProvider->getClass($className);
118-
119-
return $classReflection->isSubclassOfClass(
120-
$this->reflectionProvider->getClass($this->getClass()),
121-
);
122-
}
123-
}
124-
}
125-
}
126-
127-
$classNames = $returnType->getObjectClassNames();
128-
129-
if (count($classNames) > 0) {
130-
$className = $classNames[0];
131-
132-
if ($className === ActiveQuery::class) {
133-
return true;
134-
}
135-
136-
if ($this->reflectionProvider->hasClass($className)) {
137-
$classReflection = $this->reflectionProvider->getClass($className);
138-
139-
return $classReflection->isSubclassOfClass($this->reflectionProvider->getClass(ActiveQuery::class));
140-
}
141-
}
142-
143-
return $returnType::class === GenericObjectType::class && $returnType->getClassName() === ActiveQuery::class;
144-
}
145-
14678
/**
14779
* Infers the return type for a static method call on an {@see ActiveRecord} class based on method signature and
14880
* context.
@@ -225,30 +157,71 @@ public function getTypeFromStaticMethodCall(
225157
}
226158

227159
/**
228-
* Determines whether the specified class is {@see ActiveRecord} or a subclass.
160+
* Determines whether the specified static method is supported for dynamic return type inference.
229161
*
230-
* Checks if the given class name corresponds to the {@see ActiveRecord} base class or any of its subclasses by
231-
* leveraging the reflection provider.
162+
* Inspects the method's return type and class context to decide if the static method should be handled by this
163+
* extension for dynamic return type analysis.
232164
*
233-
* This is used to ensure type compatibility and accurate type inference for static {@see ActiveRecord} methods
234-
* during PHPStan analysis.
165+
* This includes methods returning `$this`, union types containing {@see ActiveRecord} subclasses, or types related
166+
* to {@see ActiveQuery}.
235167
*
236-
* This method is essential for supporting dynamic return type inference in scenarios where union types or generic
237-
* {@see ActiveRecord} subclasses are involved, enabling precise type checks and autocompletion.
168+
* This method enables PHPStan to apply custom type inference for static {@see ActiveRecord} query methods ensuring
169+
* accurate autocompletion and static analysis for methods such as {@see ActiveRecord::findOne()},
170+
* {@see ActiveRecord::findAll()}, and custom query builders.
238171
*
239-
* @param string $className Fully qualified class name to check.
172+
* @param MethodReflection $methodReflection Reflection instance for the method being analyzed.
240173
*
241-
* @return bool `true` if the class is {@see ActiveRecord} or a subclass; `false` otherwise.
174+
* @return bool `true` if the static method is supported for dynamic return type inference; `false` otherwise.
242175
*/
243-
private function isActiveRecordClass(string $className): bool
176+
public function isStaticMethodSupported(MethodReflection $methodReflection): bool
244177
{
245-
if ($this->reflectionProvider->hasClass($className) === false) {
178+
$variants = $methodReflection->getVariants();
179+
180+
if (count($variants) === 0) {
246181
return false;
247182
}
248183

249-
return $this->reflectionProvider->getClass($className)->isSubclassOfClass(
250-
$this->reflectionProvider->getClass(ActiveRecord::class),
251-
);
184+
$returnType = $variants[0]->getReturnType();
185+
186+
if ($returnType::class === ThisType::class) {
187+
return true;
188+
}
189+
190+
if ($returnType::class === UnionType::class) {
191+
foreach ($returnType->getTypes() as $type) {
192+
$classNames = $type->getObjectClassNames();
193+
194+
if (count($classNames) > 0) {
195+
$className = $classNames[0];
196+
197+
if ($this->reflectionProvider->hasClass($className)) {
198+
$classReflection = $this->reflectionProvider->getClass($className);
199+
200+
return $classReflection->isSubclassOfClass(
201+
$this->reflectionProvider->getClass($this->getClass()),
202+
);
203+
}
204+
}
205+
}
206+
}
207+
208+
$classNames = $returnType->getObjectClassNames();
209+
210+
if (count($classNames) > 0) {
211+
$className = $classNames[0];
212+
213+
if ($className === ActiveQuery::class) {
214+
return true;
215+
}
216+
217+
if ($this->reflectionProvider->hasClass($className)) {
218+
$classReflection = $this->reflectionProvider->getClass($className);
219+
220+
return $classReflection->isSubclassOfClass($this->reflectionProvider->getClass(ActiveQuery::class));
221+
}
222+
}
223+
224+
return $returnType::class === GenericObjectType::class && $returnType->getClassName() === ActiveQuery::class;
252225
}
253226

254227
/**
@@ -277,4 +250,31 @@ private function isActiveQueryClass(string $className): bool
277250
$this->reflectionProvider->getClass(ActiveQuery::class),
278251
);
279252
}
253+
254+
/**
255+
* Determines whether the specified class is {@see ActiveRecord} or a subclass.
256+
*
257+
* Checks if the given class name corresponds to the {@see ActiveRecord} base class or any of its subclasses by
258+
* leveraging the reflection provider.
259+
*
260+
* This is used to ensure type compatibility and accurate type inference for static {@see ActiveRecord} methods
261+
* during PHPStan analysis.
262+
*
263+
* This method is essential for supporting dynamic return type inference in scenarios where union types or generic
264+
* {@see ActiveRecord} subclasses are involved, enabling precise type checks and autocompletion.
265+
*
266+
* @param string $className Fully qualified class name to check.
267+
*
268+
* @return bool `true` if the class is {@see ActiveRecord} or a subclass; `false` otherwise.
269+
*/
270+
private function isActiveRecordClass(string $className): bool
271+
{
272+
if ($this->reflectionProvider->hasClass($className) === false) {
273+
return false;
274+
}
275+
276+
return $this->reflectionProvider->getClass($className)->isSubclassOfClass(
277+
$this->reflectionProvider->getClass(ActiveRecord::class),
278+
);
279+
}
280280
}

0 commit comments

Comments
 (0)