symfony: [PropertyInfo] Optional dependency phpdocumenter/reflection-docblock is a risk when already installed as dev-dependency

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.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 16 (16 by maintainers)

Commits related to this issue

Most upvoted comments

What bothers me is that we would break applications that documented their dependencies correctly in order to work around a problem of apps with incorrect dependencies. I kinda start to like the idea of a bridge package for phpDocumentor, I must admit.

related to #39356 I guess

It does thanks. Maybe https://packagist.org/packages/maglnet/composer-require-checker could help. I still think creating a separate package would be a too high maintenance overhead for the situation. You have a dep issue, it’s fixed now…

@nicolas-grekas I’m not sure if I understand your question correctly, but I’ll try to give you some more context. This problem happened in a library I was working on that used the Symfony Serializer component as a dependency (and therefore also the PropertyInfo component), so not a full Symfony application that has a DI container. The library is used to communicate with an external service and it had to do some (de)serialization. In that library, when I construct the Serializer, I add an ObjectNormalizer with a PropertyInfoExtractor that uses a PhpDocExtractor as type extractor. The library also requires phpunit/phpunit as a dev-dependency, and therefore I got no errors and all tests passed. At that point, I was not aware that I had to require phpdocumentor/reflection-docblock separately.

Then, when I required the library in one of the PHP applications that needed to communicate with this external service, things still worked fine, because the applications itself also required phpunit/phpunit. But then, when we deployed the application, we got the error that phpdocumentor/reflection-docblock was not installed.

It took some time to figure out why this did work during development, but not in production. In the end, I of course required phpdocumentor/reflection-docblock as a dependency in the library, because that seemed to be required when using the PhpDocExtractor. But in my opinion, this is bad developer experience.

Does this answer your question?