ProxyGenerator fails with optional parameters
jesusangel opened this issue · 7 comments
Hello,
First of all, this is my environment:
- OS: Debian Buster
- PHP 8.0
- Doctrine Common v2.10.0-1
It seems that in PHP8 the ReflectionType name starts with a question mark when the parameter is optional, as you can check here: https://3v4l.org/3RUWo
The method formatType of ProxyGenerator checks that the type's class exists using class_exists($name) where $name contains the parameter's type's name. When the parameter is optional, this name starts with '?', for example: '?Company\Project\MyClass' and the check fails and an UnexpectedValueException::invalidParameterTypeHint exception is thrown.
Maybe Doctrine should check for this, and remove that leading question mark before checking for the existence of the class.
Regards,
Is it possible to upgrade doctrine/common to ^3.1
? The problem is fixed there and the v2.x branch of Common isn't actually PHP 8 compatible (even though it claims it is).
Doctrine Common v2.10.0-1
There is no such release. If you're actually using 2.10, please upgrade to 2.13 first and see if the problem persists.
Thank you both for your answers. @alcaeus I am using Debian Buster and 2.10 is the last version of the package doctrine-common available as you can check here: https://packages.debian.org/buster/php-doctrine-common. Anyway, I will manually upgrade to 2.13 and I will check if the problem persists. However, reading the code it seems to me that the problem will persist as the code has not changed very much:
private function formatType(
\ReflectionType $type,
\ReflectionMethod $method,
\ReflectionParameter $parameter = null
) {
$name = $type->getName();
$nameLower = strtolower($name);
if ('self' === $nameLower) {
$name = $method->getDeclaringClass()->getName();
}
if ('parent' === $nameLower) {
$name = $method->getDeclaringClass()->getParentClass()->getName();
}
if ( ! $type->isBuiltin() && ! class_exists($name) && ! interface_exists($name)) {
if (null !== $parameter) {
throw UnexpectedValueException::invalidParameterTypeHint(
$method->getDeclaringClass()->getName(),
$method->getName(),
$parameter->getName()
);
}
throw UnexpectedValueException::invalidReturnTypeHint(
$method->getDeclaringClass()->getName(),
$method->getName()
);
}
@beberlei I would prefer to keep using the Doctrine's v2.x branch right now. Nevertheless, if I have no alternative, I will upgrade Doctrine to 3.1.
How about trimming the leading '?' for optional parameters at the begining of the formatType function? I think this would work:
$name = ltrim($type->getName(), '?');
2.10 is not compatible with PHP 8 if you check it's composer.json. If you can reproduce this in 2.13 with a test (PR with failing build would be perfect, but posting a reproducer is enough) I'm happy to take a look. 2.10 won't get bug fixes anyways, so you'd always have to upgrade.
As for switching to 3.x, why not? We've removed some old packages that have long been extracted and there shouldn't be adverse consequences.
Debian seems to have backported PHP 8 support into their forked doctrine/common package versioned 2.10.1. This is not supported by us, please talk to Debian maintainers.
Ah no, they still have "php": "^7.1"
in the version constraints, but it seems they don't prevent installation with PHP 8. How do you have PHP 8 on Buster anyways? Through ondrejs packages? i would really recommend you not to use the debian packages but use Composer directly, otherwise use the Buster recommended php version and not 8.0
I appreciate your help. I used the sury repository to install PHP8 in Buster. Finally, I have installed PHP 7.3 and I'll stick to that version until I upgrade to PHP8 and Doctrine 3.x.