nodeTypeResolver = $nodeTypeResolver; $this->nodeNameResolver = $nodeNameResolver; $this->reflectionProvider = $reflectionProvider; } public function isCastableArrayType(\PhpParser\Node\Expr $expr) : bool { if (!$expr instanceof \PhpParser\Node\Expr\PropertyFetch) { return \false; } $callerObjectType = $this->nodeTypeResolver->resolve($expr->var); $propertyName = $this->nodeNameResolver->getName($expr->name); if (!\is_string($propertyName)) { return \false; } if ($callerObjectType instanceof \PHPStan\Type\UnionType) { $callerObjectType = $callerObjectType->getTypes()[0]; } if (!$callerObjectType instanceof \PHPStan\Type\TypeWithClassName) { return \false; } if (\is_a($callerObjectType->getClassName(), \PhpParser\Node\Stmt::class, \true)) { return \false; } if (\is_a($callerObjectType->getClassName(), \PhpParser\Node\Expr\Array_::class, \true)) { return \false; } // this must be handled reflection, as PHPStan ReflectionProvider does not provide default values for properties in any way $classReflection = $this->reflectionProvider->getClass($callerObjectType->getClassName()); $nativeReflectionClass = $classReflection->getNativeReflection(); $propertiesDefaults = $nativeReflectionClass->getDefaultProperties(); if (!\array_key_exists($propertyName, $propertiesDefaults)) { return \false; } $propertyDefaultValue = $propertiesDefaults[$propertyName]; return $propertyDefaultValue === null; } }