Skip to content

Commit

Permalink
Merge pull request #836 from kukulich/get-class
Browse files Browse the repository at this point in the history
Added `ReflectionNamedType::getClass()`
  • Loading branch information
Ocramius authored Nov 7, 2021
2 parents d2acbbf + 9388c3e commit e52cbda
Show file tree
Hide file tree
Showing 14 changed files with 405 additions and 86 deletions.
23 changes: 22 additions & 1 deletion src/Reflection/ReflectionClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ private function createMethodsFromTrait(ReflectionMethod $method): array
$method->getDeclaringClass()->getDeclaringNamespaceAst(),
$method->getDeclaringClass(),
$this,
$this,
$aliasMethodName,
);

Expand Down Expand Up @@ -282,7 +283,25 @@ private function getParentMethods(): array
return array_merge(
[],
...array_map(
static fn (ReflectionClass $ancestor): array => $ancestor->getMethods(),
function (ReflectionClass $ancestor): array {
return array_map(
function (ReflectionMethod $method): ReflectionMethod {
$methodAst = $method->getAst();
assert($methodAst instanceof ClassMethod);

return ReflectionMethod::createFromNode(
$this->reflector,
$methodAst,
$this->locatedSource,
$method->getDeclaringClass()->getDeclaringNamespaceAst(),
$method->getDeclaringClass(),
$method->getImplementingClass(),
$this,
);
},
$ancestor->getMethods(),
);
},
array_filter([$this->getParentClass()]),
),
);
Expand Down Expand Up @@ -443,6 +462,7 @@ public function getImmediateMethods(?int $filter = null): array
$this->declaringNamespace,
$this,
$this,
$this,
),
$this->node->getMethods(),
);
Expand Down Expand Up @@ -488,6 +508,7 @@ private function addEnumMethods(array $methods): array
$this->declaringNamespace,
$this,
$this,
$this,
);

$methods[] = $createMethod('cases', [], 'array');
Expand Down
2 changes: 1 addition & 1 deletion src/Reflection/ReflectionEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public function getBackingType(): ReflectionNamedType
throw new LogicException('This enum does not have a backing type available');
}

$backingType = ReflectionNamedType::createFromNode($this->node->scalarType);
$backingType = ReflectionNamedType::createFromNode($this->reflector, $this, $this->node->scalarType);
assert($backingType instanceof ReflectionNamedType);

return $backingType;
Expand Down
4 changes: 3 additions & 1 deletion src/Reflection/ReflectionFunctionAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,9 @@ private function createReturnType(): ReflectionNamedType|ReflectionUnionType|Ref
return null;
}

return ReflectionType::createFromNode($returnType);
assert($this instanceof ReflectionMethod || $this instanceof ReflectionFunction);

return ReflectionType::createFromNode($this->reflector, $this, $returnType);
}

/**
Expand Down
14 changes: 10 additions & 4 deletions src/Reflection/ReflectionIntersectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Roave\BetterReflection\Reflection;

use PhpParser\Node\IntersectionType;
use Roave\BetterReflection\Reflector\Reflector;

use function array_filter;
use function array_map;
Expand All @@ -15,11 +16,16 @@ class ReflectionIntersectionType extends ReflectionType
/** @var list<ReflectionNamedType> */
private array $types;

public function __construct(IntersectionType $type, bool $allowsNull)
{
parent::__construct($allowsNull);
public function __construct(
Reflector $reflector,
ReflectionParameter|ReflectionMethod|ReflectionFunction|ReflectionEnum|ReflectionProperty $owner,
IntersectionType $type,
bool $allowsNull,
) {
parent::__construct($reflector, $owner, $allowsNull);

$this->types = array_filter(
array_map(static fn ($type): ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType => ReflectionType::createFromNode($type), $type->types),
array_map(static fn ($type): ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType => ReflectionType::createFromNode($reflector, $owner, $type), $type->types),
static fn (ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType $type): bool => $type instanceof ReflectionNamedType,
);
}
Expand Down
15 changes: 15 additions & 0 deletions src/Reflection/ReflectionMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class ReflectionMethod extends ReflectionFunctionAbstract

private ReflectionClass $implementingClass;

private ReflectionClass $currentClass;

private MethodNode $methodNode;

private ?string $aliasName;
Expand All @@ -46,11 +48,13 @@ public static function createFromNode(
?Namespace_ $namespace,
ReflectionClass $declaringClass,
ReflectionClass $implementingClass,
ReflectionClass $currentClass,
?string $aliasName = null,
): self {
$method = new self($reflector, $node, $locatedSource, $namespace);
$method->declaringClass = $declaringClass;
$method->implementingClass = $implementingClass;
$method->currentClass = $currentClass;
$method->methodNode = $node;
$method->aliasName = $aliasName;

Expand Down Expand Up @@ -250,11 +254,22 @@ public function getDeclaringClass(): ReflectionClass
return $this->declaringClass;
}

/**
* Get the class that implemented the method based on trait use.
*/
public function getImplementingClass(): ReflectionClass
{
return $this->implementingClass;
}

/**
* Get the current reflected class.
*/
public function getCurrentClass(): ReflectionClass
{
return $this->currentClass;
}

/**
* @throws ClassDoesNotExist
* @throws NoObjectProvided
Expand Down
56 changes: 53 additions & 3 deletions src/Reflection/ReflectionNamedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@

namespace Roave\BetterReflection\Reflection;

use LogicException;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use Roave\BetterReflection\Reflector\Reflector;

use function array_key_exists;
use function assert;
use function sprintf;
use function strtolower;

class ReflectionNamedType extends ReflectionType
Expand All @@ -32,9 +36,13 @@ class ReflectionNamedType extends ReflectionType

private string $name;

public function __construct(Identifier|Name $type, bool $allowsNull)
{
parent::__construct($allowsNull);
public function __construct(
Reflector $reflector,
ReflectionParameter|ReflectionMethod|ReflectionFunction|ReflectionEnum|ReflectionProperty $owner,
Identifier|Name $type,
bool $allowsNull,
) {
parent::__construct($reflector, $owner, $allowsNull);

$this->name = $type->toString();
}
Expand All @@ -54,6 +62,48 @@ public function isBuiltin(): bool
return array_key_exists(strtolower($this->name), self::BUILT_IN_TYPES);
}

public function getClass(): ReflectionClass
{
if (! $this->isBuiltin()) {
return $this->reflector->reflectClass($this->name);
}

if (
$this->owner instanceof ReflectionEnum
|| $this->owner instanceof ReflectionFunction
|| ($this->owner instanceof ReflectionParameter && $this->owner->getDeclaringFunction() instanceof ReflectionFunction)
) {
throw new LogicException(sprintf('The type %s cannot be resolved to class', $this->name));
}

if (strtolower($this->name) === 'self') {
return $this->owner->getDeclaringClass();
}

if (strtolower($this->name) === 'parent') {
$class = $this->owner->getDeclaringClass();
assert($class instanceof ReflectionClass);
$parentClass = $class->getParentClass();
assert($parentClass instanceof ReflectionClass);

return $parentClass;
}

if (
! $this->owner instanceof ReflectionProperty
&& strtolower($this->name) === 'static'
) {
$method = $this->owner instanceof ReflectionMethod
? $this->owner
: $this->owner->getDeclaringFunction();
assert($method instanceof ReflectionMethod);

return $method->getCurrentClass();
}

throw new LogicException(sprintf('The type %s cannot be resolved to class', $this->name));
}

public function __toString(): string
{
$name = '';
Expand Down
47 changes: 9 additions & 38 deletions src/Reflection/ReflectionParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ public function getType(): ReflectionNamedType|ReflectionUnionType|ReflectionInt

$allowsNull = $this->isDefaultValueAvailable() && $this->getDefaultValue() === null && ! $this->isDefaultValueConstant();

return ReflectionType::createFromNode($type, $allowsNull);
return ReflectionType::createFromNode($this->reflector, $this, $type, $allowsNull);
}

/**
Expand Down Expand Up @@ -463,17 +463,6 @@ public function getDefaultValueConstantName(): string
* Gets a ReflectionClass for the type hint (returns null if not a class)
*/
public function getClass(): ?ReflectionClass
{
$className = $this->getClassName();

if ($className === null) {
return null;
}

return $this->reflector->reflectClass($className);
}

private function getClassName(): ?string
{
$type = $this->getType();

Expand All @@ -487,43 +476,25 @@ private function getClassName(): ?string

if ($type instanceof ReflectionUnionType) {
foreach ($type->getTypes() as $innerType) {
$innerTypeClassName = $this->getClassNameFromNamedType($innerType);
if ($innerTypeClassName !== null) {
return $innerTypeClassName;
$innerTypeClass = $this->getClassFromNamedType($innerType);
if ($innerTypeClass !== null) {
return $innerTypeClass;
}
}

return null;
}

return $this->getClassNameFromNamedType($type);
return $this->getClassFromNamedType($type);
}

private function getClassNameFromNamedType(ReflectionNamedType $namedType): ?string
private function getClassFromNamedType(ReflectionNamedType $namedType): ?ReflectionClass
{
$typeHint = $namedType->getName();

if ($typeHint === 'self') {
$declaringClass = $this->getDeclaringClass();
assert($declaringClass instanceof ReflectionClass);

return $declaringClass->getName();
}

if ($typeHint === 'parent') {
$declaringClass = $this->getDeclaringClass();
assert($declaringClass instanceof ReflectionClass);
$parentClass = $declaringClass->getParentClass();
assert($parentClass instanceof ReflectionClass);

return $parentClass->getName();
}

if ($namedType->isBuiltin()) {
try {
return $namedType->getClass();
} catch (LogicException) {
return null;
}

return $typeHint;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Reflection/ReflectionProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ public function getType(): ReflectionNamedType|ReflectionUnionType|ReflectionInt
return null;
}

return ReflectionType::createFromNode($type);
return ReflectionType::createFromNode($this->reflector, $this, $type);
}

/**
Expand Down
22 changes: 15 additions & 7 deletions src/Reflection/ReflectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,41 @@
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\UnionType;
use Roave\BetterReflection\Reflector\Reflector;

abstract class ReflectionType
{
protected function __construct(private bool $allowsNull)
{
protected function __construct(
protected Reflector $reflector,
protected ReflectionParameter|ReflectionMethod|ReflectionFunction|ReflectionEnum|ReflectionProperty $owner,
private bool $allowsNull,
) {
}

/**
* @internal
*/
public static function createFromNode(Identifier|Name|NullableType|UnionType|IntersectionType $type, bool $forceAllowsNull = false): ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType
{
public static function createFromNode(
Reflector $reflector,
ReflectionParameter|ReflectionMethod|ReflectionFunction|ReflectionEnum|ReflectionProperty $owner,
Identifier|Name|NullableType|UnionType|IntersectionType $type,
bool $forceAllowsNull = false,
): ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType {
$allowsNull = $forceAllowsNull;
if ($type instanceof NullableType) {
$type = $type->type;
$allowsNull = true;
}

if ($type instanceof Identifier || $type instanceof Name) {
return new ReflectionNamedType($type, $allowsNull);
return new ReflectionNamedType($reflector, $owner, $type, $allowsNull);
}

if ($type instanceof IntersectionType) {
return new ReflectionIntersectionType($type, $allowsNull);
return new ReflectionIntersectionType($reflector, $owner, $type, $allowsNull);
}

return new ReflectionUnionType($type, $allowsNull);
return new ReflectionUnionType($reflector, $owner, $type, $allowsNull);
}

/**
Expand Down
13 changes: 9 additions & 4 deletions src/Reflection/ReflectionUnionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Roave\BetterReflection\Reflection;

use PhpParser\Node\UnionType;
use Roave\BetterReflection\Reflector\Reflector;

use function array_filter;
use function array_map;
Expand All @@ -15,12 +16,16 @@ class ReflectionUnionType extends ReflectionType
/** @var list<ReflectionNamedType> */
private array $types;

public function __construct(UnionType $type, bool $allowsNull)
{
parent::__construct($allowsNull);
public function __construct(
Reflector $reflector,
ReflectionParameter|ReflectionMethod|ReflectionFunction|ReflectionEnum|ReflectionProperty $owner,
UnionType $type,
bool $allowsNull,
) {
parent::__construct($reflector, $owner, $allowsNull);

$this->types = array_filter(
array_map(static fn ($type): ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType => ReflectionType::createFromNode($type), $type->types),
array_map(static fn ($type): ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType => ReflectionType::createFromNode($reflector, $owner, $type), $type->types),
static fn (ReflectionNamedType|ReflectionUnionType|ReflectionIntersectionType $type): bool => $type instanceof ReflectionNamedType,
);
}
Expand Down
Loading

0 comments on commit e52cbda

Please sign in to comment.