8000 [DependencyInjection] Private services are not always private in dumped container · Issue #19117 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DependencyInjection] Private services are not always private in dumped container #19117

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
hhamon opened this issue Jun 20, 2016 · 5 comments
Closed

Comments

@hhamon
Copy link
Contributor
hhamon commented Jun 20, 2016

While delivering a training on Symfony 3.1 last week, my students and I stumbled upon an unexpected behavior. Some private services we defined were public in the end in the final dumped container. It was possible to request them outside of the container thanks to its get() method.

Consider the following scenarii.

Use Case 1: Orphan Private Service is Removed

services:
    app.foo:
        class: Foo
        public: false

This use case works as expected. An orphan private service is always removed from the final dumped container. It can never be requested to the container.

Use Case 2 : Private Service Referenced Once is Inlined

services:
    app.bar:
        class: Bar
        arguments: ['@app.foo']
    app.foo:
        class: Foo
        public: false

This use case also works as expected. The private app.foo service is inlined in the generated getApp_BarService() method in the compiled container. The app.foo service cannot be requested outside of the container because it's inlined.

Use Case 3 : Private Service Referenced More Than Once is Shared and Public

This is the problem! Consider the following definition.

services:
    app.baz:
        class: Baz
        arguments: ['@app.foo']
    app.bar:
        class: Bar
        arguments: ['@app.foo']
    app.foo:
        class: Foo
        public: false

In this situation, the private service app.foo is referenced twice by two public services. As such the compiled container generates a protected getApp_FooService() method that will create the app.foo service on demand when its requested with the Container::get() method. The app.foo service reference will be stored in the $services array of the dumped container.

It's also possible to request this service outside of the container:

$container->get('app.foo');

The final dumped container looks like the following in my Symfony 3.1 SE project:

<?php

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;

/**
 * appDevDebugProjectContainer.
 *
 * This class has been auto-generated
 * by the Symfony Dependency Injection Component.
 */
class appDevDebugProjectContainer extends Container
{
    private $parameters;
    private $targetDirs = array();

    /**
     * Constructor.
     */
    public function __construct()
    {
        $dir = __DIR__;
        for ($i = 1; $i <= 5; ++$i) {
            $this->targetDirs[$i] = $dir = dirname($dir);
        }
        $this->parameters = $this->getDefaultParameters();

        $this->services = array();
        $this->methodMap = array(
            'annotation_reader' => 'getAnnotationReaderService',
            'app.bar' => 'getApp_BarService',
            'app.baz' => 'getApp_BazService',
            'app.foo' => 'getApp_FooService',
            // ...
        );
        // ...
    }

    // ...

    /**
     * Gets the 'app.foo' service.
     *
     * This service is shared.
     * This method always returns the same instance of the service.
     *
     * This service is private.
     * If you want to be able to request this service from the container directly,
     * make it public, otherwise you might end up with broken code.
     *
     * @return \Foo A Foo instance.
     */
    protected function getApp_FooService()
    {
        return $this->services['app.foo'] = new \Foo();
    }

    /**
     * Gets the 'app.bar' service.
     *
     * This service is shared.
     * This method always returns the same instance of the service.
     *
     * @return \Bar A Bar instance.
     */
    protected function getApp_BarService()
    {
        return $this->services['app.bar'] = new \Bar($this->get('app.foo'));
    }

    /**
     * Gets the 'app.baz' service.
     *
     * This service is shared.
     * This method always returns the same instance of the service.
     *
     * @return \Baz A Baz instance.
     */
    protected function getApp_BazService()
    {
        return $this->services['app.baz'] = new \Baz($this->get('app.foo'));
    }
}
@xabbuh
Copy link
Member
xabbuh commented Jun 20, 2016

see #15703

@hhamon
Copy link
Contributor Author
hhamon commented Jun 20, 2016

Thanks @xabbuh !

@nicolas-grekas
Copy link
Member

So, shouldn't we deprecated this behavior and make private services really private?

@fabpot
Copy link
Member
fabpot commented Jun 20, 2016

Indeed. Making them "really" private is just a matter of changing their id by a random one. Should be easy enough to implement.

@hhamon
Copy link
Contributor Author
hhamon commented Jun 20, 2016

I'll fix it then ;)

hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 22, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 22, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 22, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 22, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 22, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 23, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 23, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 23, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 27, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 27, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 27, 2016
hhamon pushed a commit to hhamon/symfony that referenced this issue Jun 28, 2016
fabpot added a commit that referenced this issue Jun 29, 2016
…ed services. (hhamon)

This PR was merged into the 3.2-dev branch.

Discussion
----------

[DependencyInjection] deprecate access to private shared services.

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #19117
| License       | MIT
| Doc PR        | ~

Commits
-------

4ed70c4 [DependencyInjection] deprecate access to private shared services. Fixes issue #19117.
@fabpot fabpot closed this as completed Jun 29, 2016
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

5 participants
0