Skip to content

Commit

Permalink
ClassReflection: make getTraits recursive
Browse files Browse the repository at this point in the history
  • Loading branch information
iamrgroot committed Jun 17, 2021
1 parent 498b868 commit 07d78b2
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 4 deletions.
31 changes: 27 additions & 4 deletions src/Reflection/ClassReflection.php
Expand Up @@ -670,13 +670,36 @@ public function getInterfaces(): array
}

/**
* @return \PHPStan\Reflection\ClassReflection[]
* @return array<string, \PHPStan\Reflection\ClassReflection>
*/
public function getTraits(): array
public function getTraits(bool $recursive = false): array
{
return array_map(function (\ReflectionClass $trait): ClassReflection {
$traits = [];

if ($recursive) {
foreach ($this->collectTraits($this->getNativeReflection()) as $trait) {
$traits[$trait->getName()] = $trait;
}
} else {
$traits = $this->getNativeReflection()->getTraits();
}

$traits = array_map(function (\ReflectionClass $trait): ClassReflection {
return $this->reflectionProvider->getClass($trait->getName());
}, $this->getNativeReflection()->getTraits());
}, $traits);

if ($recursive) {
$parentClass = $this->getNativeReflection()->getParentClass();

if ($parentClass !== false) {
return array_merge(
$traits,
$this->reflectionProvider->getClass($parentClass->getName())->getTraits(true)
);
}
}

return $traits;
}

/**
Expand Down
96 changes: 96 additions & 0 deletions tests/PHPStan/Reflection/ClassReflectionTest.php
Expand Up @@ -220,4 +220,100 @@ public function testDeprecatedConstantFromAnotherFile(): void
$this->assertTrue($constant->isDeprecated()->yes());
}

/**
* @dataProvider dataNestedRecursiveTraits
* @param class-string $className
* @param array<class-string, class-string> $expected
* @param bool $recursive
*/
public function testGetTraits(string $className, array $expected, bool $recursive): void
{
$reflectionProvider = $this->createBroker();

$this->assertSame(
array_map(
static function (ClassReflection $classReflection): string {
return $classReflection->getNativeReflection()->getName();
},
$reflectionProvider->getClass($className)->getTraits($recursive)
),
$expected
);
}

public function dataNestedRecursiveTraits(): array
{
return [
[
\NestedTraits\NoTrait::class,
[],
false,
],
[
\NestedTraits\NoTrait::class,
[],
true,
],
[
\NestedTraits\Foo::class,
[
\NestedTraits\FooTrait::class => \NestedTraits\FooTrait::class,
],
false,
],
[
\NestedTraits\Foo::class,
[
\NestedTraits\FooTrait::class => \NestedTraits\FooTrait::class,
],
true,
],
[
\NestedTraits\Bar::class,
[
\NestedTraits\BarTrait::class => \NestedTraits\BarTrait::class,
],
false,
],
[
\NestedTraits\Bar::class,
[
\NestedTraits\BarTrait::class => \NestedTraits\BarTrait::class,
\NestedTraits\FooTrait::class => \NestedTraits\FooTrait::class,
],
true,
],
[
\NestedTraits\Baz::class,
[
\NestedTraits\BazTrait::class => \NestedTraits\BazTrait::class,
],
false,
],
[
\NestedTraits\Baz::class,
[
\NestedTraits\BazTrait::class => \NestedTraits\BazTrait::class,
\NestedTraits\BarTrait::class => \NestedTraits\BarTrait::class,
\NestedTraits\FooTrait::class => \NestedTraits\FooTrait::class,
],
true,
],
[
\NestedTraits\BazChild::class,
[],
false,
],
[
\NestedTraits\BazChild::class,
[
\NestedTraits\BazTrait::class => \NestedTraits\BazTrait::class,
\NestedTraits\BarTrait::class => \NestedTraits\BarTrait::class,
\NestedTraits\FooTrait::class => \NestedTraits\FooTrait::class,
],
true,
],
];
}

}
40 changes: 40 additions & 0 deletions tests/PHPStan/Reflection/data/NestedTraits.php
@@ -0,0 +1,40 @@
<?php

namespace NestedTraits;

trait FooTrait
{
}

trait BarTrait
{
use FooTrait;
}

trait BazTrait
{
use BarTrait;
}

class NoTrait
{
}

class Foo
{
use FooTrait;
}

class Bar
{
use BarTrait;
}

class Baz
{
use BazTrait;
}

class BazChild extends Baz
{
}

0 comments on commit 07d78b2

Please sign in to comment.