Skip to content

[FrameworkBundle] TestContainer @internal annotation conflicts with official testing usage #60299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mickverm opened this issue Apr 29, 2025 · 11 comments

Comments

@mickverm
Copy link

mickverm commented Apr 29, 2025

Symfony version(s) affected

5.x, 6.x, 7.x

Description

When using PHPStan 2.1.13 with bleeding edge enabled, calls to TestContainer::get() and TestContainer::set() as used in the official Symfony testing documentation (https://symfony.com/doc/current/testing.html#integration-tests) trigger the following errors:

Call to method get() of internal class Symfony\Bundle\FrameworkBundle\Test\TestContainer from outside its root namespace Symfony.

Call to method set() of internal class Symfony\Bundle\FrameworkBundle\Test\TestContainer from outside its root namespace Symfony.

These methods are essential for setting up integration tests as per Symfony's own recommendations. However, PHPStan is flagging them due to the @internal annotation on the TestContainer class.

How to reproduce

See: phpstan/phpstan#12941

Possible Solution

Either:

  • Remove or reconsider the @internal annotation on TestContainer, or
  • Add @api or similar visibility annotations to the get() and set() methods to clarify their intended use in test environments.

Additional Context

No response

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Apr 29, 2025

Sorry I cannot check on my own: where does Symfony expose this class as an "api" type?
To me, this is legit as internal since all cases where TestContainer is used should be typed as ContainerInterface, preserving the actual class as an implementation detail, thus internal.

@ro0NL
Copy link
Contributor

ro0NL commented Apr 29, 2025

probably here

->set('test.service_container', TestContainer::class)

@nicolas-grekas
Copy link
Member

Thanks.
No issue on Symfony 's side then.

@codedmonkey
Copy link
Contributor

The same happens with Polyfills, for example using \IntlDateFormatter from the intl extension results in something like:

Access to constant LONG of internal class Symfony\Polyfill\Intl\Icu\IntlDateFormatter from outside its root namespace Symfony. 

Even when the intl extension is installed and the polyfill is unused.

@nicolas-grekas
Copy link
Member

Let me close since there's nothing to fix on this side: the code declares things the way it should.

@ondrejmirtes
Copy link
Contributor

ondrejmirtes commented May 1, 2025

PHPStan has to typehint KernelTestCase::getContainer() as TestContainer because it has to understand that it's okay to access private services in tests.

Some references:

I'm not using this part of Symfony so I can't judge who's right or wrong here. Anyone care to elaborate?

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 1, 2025

PHPStan has to typehint KernelTestCase::getContainer() as TestContainer because it has to understand that it's okay to access private services in tests.

I get that. I don't know how to solve this issue. To me this looks like something phpstan/SA tools needs to deal with somehow. If Symfony can help, sure, but making TestContainer non-internal doesn't seem appropriate to me here. It's just a class with some implementation in it. Making it a fully supported type would increase the surface of the BC promise for no good reasons. The fact this concretion is used to give access to private services is just an implementation detail from the PoV of Symfony.

@ondrejmirtes
Copy link
Contributor

@nicolas-grekas I agree with you. We need to mark the container fetched via this method somehow. Or we can allow fetching private services on all ContainerInterface when we're in KernelTestCase subclass.

@mickverm
Copy link
Author

mickverm commented May 5, 2025

@ondrejmirtes I annotated TestContainer.stub with @api, which seems to 'fix' the error. Is this an acceptable fix, or will this cause other issues?

@ondrejmirtes
Copy link
Contributor

@mickverm PHPStan doesn't interpret @api in any way for the @internal rules. You simply overridden the PHPDoc. You could have used @i-am-awesome and it would work the same way 😂

The problem with removing @internal from TestContainer in PHPStan stubs is that other usages of TestContainer that should be reported as invalid would not be reported.

The right solution is to remove these stubs altogether:

And fix this line https://github.com/phpstan/phpstan-symfony/blob/cf8c9c6994cf2a07c7aefddef2b26941d19efba1/src/Rules/Symfony/ContainerInterfacePrivateServiceRule.php#L46 with some other condition.

@ondrejmirtes
Copy link
Contributor

Solved in phpstan-symfony 2.0.6 thanks to phpstan/phpstan-symfony#441.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants