2016-10-02 3 views
1

Ich habe festgestellt, dass ein Symfony-Dienst nur initiiert wird (der Konstruktor wird ausgeführt), wenn eine Methode in diesem Dienst aufgerufen wird. Dies kann wichtig sein, wenn Ihr Dienst nur einen Konstruktor und keine Methoden hat.Symfony-Dienst wurde erst nach dem Methodenaufruf initiiert

Zum Beispiel:

class MyService { 

    public function __construct($someOtherService) { 

     $someOtherService->setFoo("bar"); 

    } 
} 

// And of course put this service in services.yml 

app.my_service: 
    class: AppBundle\...\MyService 
    arguments: [ app.some_other_service ] 

In diesem Fall wird der Konstruktor und somit setFoo ("bar") wird nicht aufgerufen. Warum ist das? Ist es möglich, den Dienst zu erzwingen, um zu initiieren, ohne eine (Dummy-) Methode für diesen Dienst aufzurufen?

Ich habe auch versucht, "faul: false" für die app.my_service hinzuzufügen, aber das macht keinen Unterschied.

Ich benutze Symfony 2.8.

+0

Sie interpretieren etwas falsch. Der Konstruktor wird aufgerufen, sobald Sie den Service vom Container erhalten haben. Durch die bloße Definition des Dienstes in services.yml wird der Dienst nicht instanziiert. – Cerad

+0

Ja, also verstehe ich jetzt. Und ich wollte den Dienst laden, ohne ihn aus dem Container zu bekommen. – BigJ

Antwort

3

Ihre Dienste werden niemals instanziiert, wenn sie nie verwendet werden. Um den Instanziierungsdienst zu erzwingen, können Sie sich in jede Art von Ereignislistenern einklinken, die zu Ihrem Ereignis passen, wenn Sie einen Dienst erhalten möchten (d. h. kernel.request) und diesen Dienst als Abhängigkeit an Listener übergeben. Dies wird den Dienstkonstruktor zum ersten Mal auslösen, wenn das Ereignis während der Lebensdauer des Containers ausgelöst wird.

aber ich würde eher vorschlagen, dass Sie die Architektur überprüfen. mit Service nur mit dem Konstruktor ist Unsinn

Außerdem Sie Dienste auf Instantiierung EvendDispatcher instanziiert ohne Feuerungsereignisse

Zuhörer Probe (nur weil es auf Sie Service abhängen würde):

class ServiceInstantiatorListener 
{ 
    public function onRequest(KernelEvent $kernel) 
    { 
    return; //noop, just make sure it works 
    } 

    public function instantiate($service) 
    { 
    return $service; // noop again, just call to pass service container argument 
    } 
} 

yaml config:

services: 
    my_app.service_instantiator_listener: 
    class: My\App\ServiceInstantiatorListener 
    tags: 
    - { 'name': 'kernel_events', 'event': 'kernel.request', 'method':'onRequest' } 
    calls: 
    - [instantiate, ["@my_app.weird_service_one"]] 
    - [instantiate, ["@my_app.weird_service_two"]] 

Weiter gehend können Sie Ihre Dienste mit Tag markieren und Anrufe dynamisch konfigurieren mit MyAppBundleExtension Compiler

http://symfony.com/doc/current/service_container/tags.html#create-a-compiler-pass

geht hoffe, dass ich es instanziieren Dienste bessere Möglichkeiten (das heißt einige Container interne Ereignisse) zu zwingen, aber zur Zeit habe ich den Fall nicht ich, dass müssen erfüllt werden.

+0

Ja! Ich habe bereits versucht, Event-Listener zu verwenden, um eine Lösung zu finden. Ich verstehe, was Sie meinen, und normalerweise verwende ich solche Dienste nicht, aber das ist ein Grenzfall. – BigJ

+0

@BigJ, Ich habe den Beitrag mit einigen Beispielen aktualisiert – ScayTrase

+0

Danke, ich habe dein Beispiel dazu verwendet. Obwohl ich nicht "instanziieren" verwendet habe, sondern als Argument gebe ich den Service-Container und im Listener habe ich beide meine beiden seltsamen Dienste aufgerufen;) – BigJ

1

Sie beschreiben das Verhalten eines Lazy-Loaded-Dienstes. Überprüfen Sie die Konfiguration für lazy: true und entfernen/deaktivieren Sie sie.

Symfony docs, lazy loaded service:

Die eigentliche Klasse wird so bald instanziiert werden, wie Sie mit dem Dienst zu kommunizieren versuchen (z eine seiner Methoden aufrufen).

+0

Ja, ich habe vergessen zu erwähnen, dass ich bereits versucht habe, "faul: false" für den app.my_service hinzuzufügen, aber das hat nicht funktioniert. Ich werde es meinem Beitrag hinzufügen. – BigJ

1

Sie müssen nicht wirklich eine Dummy-Methode auf dem Dienst aufrufen, um sie zu initiieren. Sie können die Service-Objekt instanziiert, indem Sie die folgende Anweisung:

$ this-> Container() -> get ('app.my_service');

+0

Das wusste ich, ich wollte den Dienst ohne diesen Anruf laden. – BigJ

Verwandte Themen