Description
Symfony version(s) affected: 3.4.47 & 4.4.19 & 5.2.3
Description
phpdocumenter/reflection-docblock
is an optional dependency of symfony/property-info
, but a required dependency when the PhpDocExtractor
is used. If someone wants to use the PhpDocExtractor
and did not install phpdocumenter/reflection-docblock
, then a clear exception is shown:
Unable to use the "PhpDocExtractor" class as the "phpdocumentor/reflection-docblock" package is not installed.
So far, so good. Install the dependency and continue.
The problemen arises when phpdocumentor/reflection-docblock
is already installed as a require-dev dependency, which is probably true in many projects: phpdocumentor/reflection-docblock
is a dependency of phpunit/phpunit
. In those cases, you don't get the exception and things work fine while developing and testing. However, after deploying the application to production, it breaks. Require-dev dependencies are not installed, and therefore phpdocumentor/reflection-docblock
is not installed, and thus the exception is only shown in production.
I think this is a big risk. There is no automated way to test this kind of things, because automated test tools also usually run with development dependencies. The underlying problem is that in composer, dev en production dependencies are mixed. Therefore, production code can (accidentally) depend on dev-dependencies.
This is of course a problem with all optional dependencies that could break the application when not present. But this use case is probably more common than others, and therefore a bigger risk.
How to reproduce
Create a project with symfony/property-info
as dependency and phpunit/phpunit
as dev-dependency and make use of the PhpDocExtractor
. This works, until installling the application without dev-dependencies.
Possible Solution
The ultimate solution is to not rely on optional dependencies, because they could be available during development, but not in production. Instead, either require the dependency or extract the piece of code that requires the dependency to a separate composer package.