Symfony: Why is method $this->get() not available

2019-08-03 06:00发布

问题:

my constructor of my Controller looks like:

function __construct(){#
    var_dump($this->get('translator'));
    exit();
}

this will give a FatalErrorException: Error: Call to a member function get() on a non-object. But why? If I use it inside a action it will work.

回答1:

This is because Controller method get needs the container property. Controller extends ContainerAware which has a method setContainer. This method let the property container be aware of the Container.
Upon instanciation, no method are called, here is the workflow

$controller = new MyController($parameters);
$controller->setContainer($container);

Before calling __construct, controller has no property $container

public function __construct($parameters)
{
    var_dump($this->container); // NULL
}

So, by calling $this->get() you are doing

$this->get('translator');
// =
$this->container->get('translator');
// =
null->get('translator');

Hence the error.

If you need the validator, you'll have to ask it in your constructor (and respect the Law of Demeter).
To do so, you'll need to declare your controller as a service

services.yml

services:
    my_controller:
        class: Acme\FooBundle\Controller\MyController
        arguments:
            - "@translator"
        calls:
            - [ "setContainer", [ "@service_container" ] ]

routing.yml

bar_route:
    path: /bar
    defaults: { _controller: my_controller:barAction }

MyController

class MyController extends Controller
{
    protected $translator;

    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }
}


回答2:

Base controller's method get() is a shortcut for $this->container->get($id);. $this->container is set in one of the controller's parent - abstract class ContainerAware. So, until object construction is finished, there is no Controller object that would have get() method. In general, container is not available in Controller's constructor.