*/
final class ArrayTypeMapper implements TypeMapperInterface
{
/**
* @readonly
* @var \Rector\TypeDeclaration\TypeAnalyzer\GenericClassStringTypeNormalizer
*/
private $genericClassStringTypeNormalizer;
/**
* @readonly
* @var \Rector\TypeDeclaration\NodeTypeAnalyzer\DetailedTypeAnalyzer
*/
private $detailedTypeAnalyzer;
/**
* @var string
*/
public const HAS_GENERIC_TYPE_PARENT = 'has_generic_type_parent';
/**
* @var \Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper
*/
private $phpStanStaticTypeMapper;
public function __construct(GenericClassStringTypeNormalizer $genericClassStringTypeNormalizer, DetailedTypeAnalyzer $detailedTypeAnalyzer)
{
$this->genericClassStringTypeNormalizer = $genericClassStringTypeNormalizer;
$this->detailedTypeAnalyzer = $detailedTypeAnalyzer;
}
// To avoid circular dependency
public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper) : void
{
$this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper;
}
public function getNodeClass() : string
{
return ArrayType::class;
}
/**
* @param ArrayType $type
*/
public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
// this cannot be handled by PHPStan $type->toPhpDocNode() as requires space removal around "|" in union type
// then e.g. "int" instead of explicit number, and nice arrays
$itemType = $type->getItemType();
$isGenericArray = $this->isGenericArrayCandidate($type);
if ($itemType instanceof UnionType && !$type instanceof ConstantArrayType && !$isGenericArray) {
return $this->createArrayTypeNodeFromUnionType($itemType);
}
if ($itemType instanceof ArrayType && $this->isGenericArrayCandidate($itemType)) {
return $this->createGenericArrayType($type, \true);
}
if ($isGenericArray) {
return $this->createGenericArrayType($type, \true);
}
$itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($itemType);
return new SpacingAwareArrayTypeNode($itemTypeNode);
}
/**
* @param ArrayType $type
*/
public function mapToPhpParserNode(Type $type, string $typeKind) : ?Node
{
return new Identifier('array');
}
private function createArrayTypeNodeFromUnionType(UnionType $unionType) : SpacingAwareArrayTypeNode
{
$unionedArrayType = [];
foreach ($unionType->getTypes() as $unionedType) {
$typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType);
$unionedArrayType[(string) $typeNode] = $typeNode;
}
if (\count($unionedArrayType) > 1) {
return new SpacingAwareArrayTypeNode(new BracketsAwareUnionTypeNode($unionedArrayType));
}
/** @var TypeNode $arrayType */
$arrayType = \array_shift($unionedArrayType);
return new SpacingAwareArrayTypeNode($arrayType);
}
private function isGenericArrayCandidate(ArrayType $arrayType) : bool
{
if ($arrayType->getKeyType() instanceof MixedType) {
return \false;
}
if ($this->isClassStringArrayType($arrayType)) {
return \true;
}
// skip simple arrays, like "string[]", from converting to obvious "array