Modernizing PHPDoc Array annotations with Rector
Auteur(s) de l'article
In one of my project, I’m working with Symfony Serializer, phpstan/phpdoc-parser and phpdocumentor/reflection-docblock to handle serialization of complex objects.
These tools rely on PHPDoc annotations to understand data types, particularly for arrays of objects.
These tools rely on PHPDoc annotations to understand data types, particularly for arrays of objects.
In PHPDocs, there are (at least) 2 possible syntaxes for array values:
/**
* @param Foo[] $arrayOfFoos
*//**
* @param array<Foo> $arrayOfFoos
*/- a list
- an array where the key is important
list<Foo> is almost the same as array<Foo> (implicit int keys) or array<int, Foo> with a slight difference you can be sure that integers in keys consecutive numbers from 0 up.But here’s where things get interesting: with recent updates to tools like Psalm, PHPStan and Symfony’s Reflection-based Serializer handler, this
Type[]|array syntax started causing issues. These tools began struggling with the ambiguity - they couldn't reliably determine whether we meant a strict list or a more flexible array structure.Exploring Options
I therefore had many solution to resolve my issue:
Faced with hundreds of annotations needing updates across my codebase, I had three potential paths:
- Manual transformation — Copy-paste and find-replace across hundreds of files. Let’s be honest, this would be error-prone and mind-numbing work. Hard pass.
- AI-assisted refactoring — Ask Claude or another AI to parse my entire codebase. While tempting, my project has thousands of files that would exceed token limits, and I wanted a repeatable, version-controllable solution.
- Rector rule — Write once, run everywhere, with the confidence that comes from automated refactoring tools. This felt like the best approach.
The choice was obvious. Plus, creating a Rector rule means other developers facing the same challenge can benefit from the work.
Plot twist: While writing this article, I discovered that PHP CS Fixer already provides a similar rule called
phpdoc_array_type that handles these transformations! Sometimes reinventing the wheel teaches you how wheels work ✨A custom Rector Rule
So, instead of manually transforming hundreds of annotations in my project, I created a custom Rector rule that automates this task.
Here’s how it works:
Here’s how it works:
The
TransformArrayTypeAnnotationRector Rulefinal class TransformArrayTypeAnnotationRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Transform array type annotations from "Type[]|array" to "array<int, Type>"',
[
new CodeSample(
'/**
* @var \App\Entity\Environment[]|array
*/
private $environments;',
'/**
* @var array<int, \App\Entity\Environment>
*/
private $environments;'
),
]
);
}
public function getNodeTypes(): array
{
return [Property::class, ClassMethod::class, Class_::class];
}
public function refactor(Node $node): ?Node
{
$docComment = $node->getDocComment();
if (null === $docComment) {
return null;
}
$originalText = $docComment->getText();
$transformedText = $this->transformDocComment($originalText);
if ($originalText === $transformedText) {
return null;
}
$node->setDocComment(new Doc($transformedText));
return $node;
}
}Configuration and Usage
In my
rector.php file, I registered my custom rule:use App\Utils\Rector\TransformArrayTypeAnnotationRector;
use Rector\Config\RectorConfig;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__.'/src',
__DIR__.'/tests',
]);
$rectorConfig->rule(TransformArrayTypeAnnotationRector::class);
};Results
Running this rule on my project automatically transformed 243 files in seconds:
./vendor/bin/rector
243/243 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
243 files with changes
Applied rules:
* TransformArrayTypeAnnotationRector
[OK] 243 files have been changed by RectorEach transformation follows this pattern:
/**
- * @var \App\Dto\Output\Category[]|array
+ * @var array<int, \App\Dto\Output\Category>
*/❤️ Love on your keyboards.
Sources
PHPStan (Sept 2025 ) PHPDoc Types.
https://phpstan.org/writing-php-code/phpdoc-types
https://phpstan.org/writing-php-code/phpdoc-types
PHP Coding Standards Fixer (Feb 2019) PHPDoc
https://cs.symfony.com/doc/rules/phpdoc/phpdoc_array_type.html
array<T> type must be used instead of T[].https://cs.symfony.com/doc/rules/phpdoc/phpdoc_array_type.html
Resources
Claude AI https://claude.ai
Helped with writing and text refinement.
Helped with writing and text refinement.
Imagen, https://deepmind.google/models/imagen/
Generated the very accurate article’s cover illustration.
Generated the very accurate article’s cover illustration.