Description
Symfony version(s) affected
4.x, 5.x, 6.0
Description
Since static-analysis tools like PHPStan or Psalm became more popular, it is not uncommon to see usage of pseudo-type like:
/** @var non-empty-string */
public $foo;
Some pseudo-types are currently supported (see #43916 introducing list
type) but others are not. We can add support for popular custom types used by PHPStan or phpDocumentor (see #44451) but there will always be less common pseudo-types which we are not aware of.
Handling of these cases is inconsistent between extractors and PhpDocExtractor
has a bug where the first character of the pseudo-type is trimmed. That one bug is quite easy to fix, but I believe handling of custom, unknown types is overall broken and we should decide how we want to handle them.
How to reproduce
Tested on v6.0.0
tag:
class TestClass {
/** @var non-empty-string */
public $foo;
/** @var some-other-custom-type */
public $bar;
}
$extractor = new \Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor();
$fooType = $extractor->getTypes(TestClass::class, 'foo'); // $builtinType: object, $class: on-empty-string (first character trimmed)
$barType = $extractor->getTypes(TestClass::class, 'bar'); // NULL
$extractor = new \Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor();
$fooType = $extractor->getTypes(TestClass::class, 'foo'); // $builtinType: object, $class: \non-empty-string (backslash prepended)
$barType = $extractor->getTypes(TestClass::class, 'bar'); // $builtinType: object, $class: \some-other-custom-type
Possible Solution
Expected result
- pseudo-types shouldn't be automatically treated as objects
- if the type cannot be correctly mapped to built-in type,
getType()
should returnnull
or throw an exception - or the developer should be informed it is a pseudo-type and decide what to do with doctype
- the doctype shouldn't be modified and returned as-is (i.e.
some-other-custom-type
and not\some-other-custom-type
) - it would be perfect if the results were consistent between both extractors
Additional Context
The first character is trimmed due to bug in \Symfony\Component\PropertyInfo\Util\PhpDocTypeHelper
. I believe there's assumption that the $docType
is FQCN with backslash prefix but in case of /** @var non-empty-string */
it is passed as-is to the function.
// src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php
// $docType: non-empty-string
private function getPhpTypeAndClass(string $docType): array
{
// ...
return ['object', substr($docType, 1)]; // substr to strip the namespace's `\`-prefix
}