|
<?php |
|
|
|
use PHPStan\Broker\Broker; |
|
use PHPStan\Broker\BrokerFactory as PhpstanBrokerFactory; |
|
use PHPStan\Reflection\ClassReflection; |
|
use PHPStan\Reflection\Php\PhpPropertyReflection; |
|
use PHPStan\Reflection\PropertiesClassReflectionExtension; |
|
use PHPStan\Reflection\PropertyReflection; |
|
use PHPStan\Type\ObjectType; |
|
|
|
class BrokerFactory extends PhpstanBrokerFactory |
|
{ |
|
public function create(): Broker |
|
{ |
|
$broker = parent::create(); |
|
|
|
$r = new \ReflectionProperty($broker, 'propertiesClassReflectionExtensions'); |
|
$r->setAccessible(true); |
|
|
|
$propertiesClassReflectionExtensions = $r->getValue($broker); |
|
array_unshift($propertiesClassReflectionExtensions, new PropertiesClassReflectionBasedOnConstructor()); |
|
$r->setValue($broker, $propertiesClassReflectionExtensions); |
|
|
|
return $broker; |
|
} |
|
} |
|
|
|
class PropertiesClassReflectionBasedOnConstructor implements PropertiesClassReflectionExtension |
|
{ |
|
public function hasProperty(ClassReflection $classReflection, string $propertyName): bool |
|
{ |
|
return $this->extractFromConstructor($classReflection->getNativeReflection(), $propertyName); |
|
} |
|
|
|
public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection |
|
{ |
|
$nativeClassReflection = $classReflection->getNativeReflection(); |
|
|
|
foreach ($nativeClassReflection->getConstructor()->getParameters() as $parameter) { |
|
if ($propertyName !== $parameter->name) { |
|
continue; |
|
} |
|
|
|
$type = new ObjectType((string) $parameter->getType()); |
|
|
|
return new PhpPropertyReflection($classReflection, $type, $nativeClassReflection->getProperty($propertyName), false, false); |
|
} |
|
} |
|
|
|
private function extractFromConstructor(\ReflectionClass $nativeClassReflection, string $propertyName) |
|
{ |
|
if (!$nativeClassReflection->hasProperty($propertyName)) { |
|
return false; |
|
} |
|
|
|
$constructor = $nativeClassReflection->getConstructor(); |
|
if (!$constructor) { |
|
return false; |
|
} |
|
|
|
foreach ($constructor->getParameters() as $parameter) { |
|
if ($propertyName !== $parameter->name) { |
|
continue; |
|
} |
|
|
|
if (!$parameter->getType()) { |
|
return false; |
|
} |
|
|
|
if ($parameter->isOptional()) { |
|
return false; |
|
} |
|
|
|
return class_exists((string) $parameter->getType()); |
|
} |
|
|
|
if ($parentClass = $nativeClassReflection->getParentClass()) { |
|
try { |
|
$reflectionClass = new \ReflectionClass($parentClass); |
|
} catch (\ReflectionException $e) { |
|
return false; |
|
} |
|
|
|
return $this->extractFromConstructor($reflectionClass, $propertyName); |
|
} |
|
|
|
return false; |
|
} |
|
} |