-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
DependencyInjectionContainer id naming problem. #11761
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
Comments
this is really weird. I never saw such behavior (and I saw errors for unknown ids though, which is even covered by tests) |
class DefaultController extends Controller
{
public function indexAction(Request $request)
{
$test= $this->get('test.with_underscores');
var_dump($test);
$test= $this->get('test.withunderscores');
var_dump($test);
$test= $this->get('test.with_underscores');
var_dump($test);
exit;
}
} outputs:
Only works with underscores. If anything other changes it will give a error. Properly caused by the strtr() in Where '_' are replaced by '' No tests found for errorhandling on naming with a underscore |
https://github.com/symfony/symfony/blob/master/src/Symfony/Component/DependencyInjection/Container.php#L216 This is only done for synchronized services. What is the exact service definition of your service? |
in services.php $container->setDefinition('test.with_underscores', new Definition('Bundle\TestBundle\Manager\TestManager'))
->addArgument(new Reference('doctrine.orm.entity_manager')); |
Think that PHP method name resolution is case insensitive. For the "FooBar" == "Foobar" // method name
"foo_bar" == "foobar" // service id To fix it the |
Using a method map would not help allowing to have |
@stof indeed, it's not possible to have Stop me if I'm wrong but to prevent collision we can do something. On prerequisite the service id |
As this is an edge which would break BC if we try to fix it, I think it's safe to mark this one as a won't fix. |
@fabpot Given that these generated methods are internal APIs, we could use a different replacement for underscores rather then using the empty char (the current generation turns snake case ids into camel cased method names, but this does not play well with the fact that PHP methods are case insensitive) |
@stof Indeed, we could keep the underscore. |
except we currently use the underscore to replace dots (which would then conflict). We need to find another way to replace dots in such case |
What needs to be done here? |
It’s a highly mind-boggling problem if the affected service has an event listener (or maybe also a compiler pass) affecting it: getting the service with a missing or extra underscore in the name will give you a new instance that hasn’t had the listener run on it. It can take a while to determine where the problem comes from. So yes, it’s an edge case, but a very time-consuming one. How performant does the conversion from service name to method name have to be? Could |
Well, we are now using a method map to handle. The remaining thing to fix this issue would be to make it the authoritative way for compiled container by dropping entirely the check for protected methods on the container. |
Looks like a good idea. I don't think we'd need to keep BC at this level, extending the generated protected methods would be really fragile anyway imho. |
the question is not about extending the generated protected methods, but about the way the list of compiled services are detected. Btw, I think keeping BC would not be hard. And the impact for people using the dumped container in Symfony would be limited to a |
LGTM, let's try this way, BC bridge included then! |
I will work on it |
here you go |
…for dumped containers (stof) This PR was merged into the 3.2-dev branch. Discussion ---------- Use the method map as authoritative list of factories for dumped containers | Q | A | ------------- | --- | Branch? | master | Bug fix? | yes | New feature? | no | BC breaks? | only for weird broken cases | Deprecations? | yes (but only for people doing weird things) | Tests pass? | yes | Fixed tickets | #11761, #19690 | License | MIT | Doc PR | n/a The initial implementation of the method factory discovery was based on a naming convention for factory methods. However, this naming convention allowed to generate the same name for multiple ids. In the meantime, a method map was introduced to solve this issue (and others). When accessing a service with a different id than the official one (thanks to ambiguities), this breaks the sharing of the service, as it creates a new instance each time and replaces the existing shared instance. This was also inconsistent between a dumped container (affected by this) and a non-dumped container (reporting a service not found error for the other id). The method map is now the authoritative way to discover available service factories. When the dumped container was generated with a method map (which is the case when using the dumper shipped in the component), the logic based on defined methods is not executed anymore. This forbids using another id than the real one to access the service (preventing to trigger the broken behavior). So this breaks BC for people being lucky (i.e. they were using the broken id only once and *before* any usage of the official id) and fixes a WTF bug for all others. When using a dumper which does not fill the method map, the old logic is still applied, but deprecation warnings are triggered on access to dumped services. Currently, this will trigger a deprecation warning for each new service instantiation. I have not found an easy way to trigger it only once (except adding a private property to remember we already triggered it, but is it worth it ?), but only people writing a project container by hand or writing their own dumper would ever see such deprecation anyway (as the core dumper generates the method map). Additionally, this makes ``getServiceIds`` faster by avoiding doing a regex match for each method in the class. Commits ------- 03b9108 Use the method map as authoritative list of factories for dumped containers
A big (belated) thank you for your work on this. I would have liked to tackle it, but I lacked some understanding of how the container works. And also, you were so quick. ;) |
Configured a service in the services.php with the id: 'testbundle.test_this'
Using it works perfect, except one strange behavior.
Calling it in your front controller with:
$this->get('testbundle.testthis');
Will throw no error, and gives you a NEW copy on the class, and replaces it in its container.
Calling $this->get('testbundle.test_this') afterwards will give you the NEW object.
Expected behavior: a error thrown of unknown id.
The text was updated successfully, but these errors were encountered: