Created
February 13, 2020 20:12
-
-
Save fbraem/c71db4954f3abc6031bc0c163cc17885 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php declare(strict_types = 1); | |
namespace App\PHPStan; | |
use PHPStan\Reflection\ClassReflection; | |
use PHPStan\Reflection\MethodReflection; | |
use PHPStan\Reflection\MethodsClassReflectionExtension; | |
use PHPStan\Analyser\OutOfClassScope; | |
use PHPStan\Type\ObjectType; | |
/** | |
* Extension to check a method call on a generic type. A method call on the generic class | |
* is forwarded to the real class using magic method __call. This | |
* extension will help PHPStan to find the method in the real class. | |
*/ | |
class EntityClassReflectionExtension implements MethodsClassReflectionExtension | |
{ | |
/** | |
* Returns true when class T (which is the real class) has a method | |
* with the given name. | |
* @param ClassReflection $classReflection | |
* @param string $methodName | |
* @return bool | |
*/ | |
public function hasMethod( | |
ClassReflection $classReflection, | |
string $methodName | |
): bool { | |
if ($classReflection->getName() === 'GenericEntity') { | |
return $this->findMethod( | |
$this->getT($classReflection), | |
$methodName | |
) != null; | |
} | |
return false; | |
} | |
/** | |
* Returns the method from the type T. | |
* @param ClassReflection $classReflection | |
* @param string $methodName | |
* @return MethodReflection | |
*/ | |
public function getMethod( | |
ClassReflection $classReflection, | |
string $methodName | |
): MethodReflection { | |
return $this->findMethod( | |
$this->getT($classReflection), | |
$methodName | |
); | |
} | |
/** | |
* T is the real class. Return the ObjectType of T. | |
* @param ClassReflection $classReflection | |
* @return ObjectType | |
*/ | |
private function getT(ClassReflection $classReflection): ObjectType | |
{ | |
return $classReflection | |
->getActiveTemplateTypeMap() | |
->getType('T'); | |
} | |
/** | |
* Find the method on the ObjectType of T. | |
* @param ObjectType $type | |
* @param string $method | |
*/ | |
private function findMethod( | |
ObjectType $type, | |
string $method | |
): ?MethodReflection { | |
if (!$type->hasMethod($method)->yes()) { | |
return null; | |
} | |
return $type->getMethod($method, new OutOfClassScope()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* A simple generic class to test the extension. | |
* @template T | |
*/ | |
class GenericEntity | |
{ | |
/** | |
* The id of the entity | |
* @var int | |
*/ | |
private $id; | |
/** | |
* The real object | |
* @var T | |
*/ | |
private $obj; | |
/** | |
* Constructor | |
* @param int $id The id of the entity | |
* @param T $domain The domain entity | |
*/ | |
public function __construct(int $id, $obj) | |
{ | |
$this->id = $id; | |
$this->obj = $obj; | |
} | |
/** | |
* Returns the id. | |
* @return int The id of the entity | |
*/ | |
public function id(): int | |
{ | |
return $this->id; | |
} | |
public function __call($method, $args) | |
{ | |
return $this->obj->{$method}(...$args); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment