Symfony - Contenitore di servizi

In qualsiasi applicazione, gli oggetti tendono ad aumentare con la crescita dell'applicazione. Man mano che gli oggetti aumentano, aumenta anche la dipendenza tra gli oggetti. La dipendenza dagli oggetti deve essere gestita correttamente per un'applicazione di successo.

Come discusso nel capitolo Componenti, Symfony fornisce un componente semplice ed efficiente, DependencyInjectionper gestire la dipendenza dagli oggetti. Un contenitore di servizi è un contenitore di oggetti con una dipendenza risolta correttamente tra di loro. Impariamo come utilizzare il componente DependencyInjection in questo capitolo.

Creiamo un file Greeterclasse. Lo scopo della classe Greeter è salutare l'utente come mostrato nell'esempio seguente.

$greeter = new Greeter('Hi'); 
$greeter->greet('Jon'); // print "Hi, Jon"

Il codice completo della classe Greeter è il seguente.

class Greeter { 
   private $greetingText; 
   
   public function __construct($greetingText) { 
      $this->greetingText = $greetingText; 
   }  
   public function greet($name) { 
      echo $this->greetingText . ", " . $name . "\r\n"; 
   } 
}

Ora, aggiungiamo la classe Greeter al contenitore del servizio. Symfony fornisceContainerBuilderper creare un nuovo contenitore. Una volta creato il contenitore, la classe Greeter può essere registrata in esso utilizzando il metodo di registro del contenitore.

use Symfony\Component\DependencyInjection\ContainerBuilder; 
$container = new ContainerBuilder(); 
$container 
   ->register('greeter', 'Greeter') 
   ->addArgument('Hi');

Qui, abbiamo utilizzato un argomento statico per specificare il testo del saluto, Ciao. Symfony fornisce anche un'impostazione dinamica dei parametri. Per utilizzare un parametro dinamico, dobbiamo scegliere un nome e specificarlo tra% e il parametro può essere impostato utilizzando il contenitoresetParameter metodo.

$container = new ContainerBuilder(); 
$container 
   ->register('greeter', 'Greeter') 
   ->addArgument('%greeter.text%');  
$container->setParameter('greeter.text', 'Hi');

Abbiamo registrato una classe Greeter con l'impostazione corretta. Ora possiamo chiedere al contenitore di fornire un oggetto Greeter configurato correttamente utilizzando il contenitoreget metodo.

$greeter = $container->get('greeter'); 
$greeter->greet('Jon'); // prints "Hi, Jon"

Abbiamo registrato con successo una classe, Greeter in container, l'abbiamo recuperata dal container e l'abbiamo utilizzata. Ora, creiamo un'altra classeUser, che usa la classe Greeter e guarda come registrarla.

class User { 
   private $greeter;  
   public $name; 
   public $age;  
   
   public function setGreeter(\Greeter $greeter) { 
      $this->greeter = $greeter; 
   }  
   public function greet() { 
      $this->greeter->greet($this->name); 
   } 
}

La classe User ottiene la classe Greeter usando uno dei suoi metodi setter,setGreeter. Per questo scenario, Symfony fornisce un metodo,addMethodCall e una classe, Reference per fare riferimento a un'altra classe come mostrato nel codice seguente.

use Symfony\Component\DependencyInjection\Reference;  
$container 
   ->register('user', 'User') 
   ->addMethodCall('setGreeter', array(new Reference('greeter')));

Infine, abbiamo registrato due classi, Greeter e Useravere una forte relazione tra di loro. Ora, possiamo recuperare in modo sicuro l'oggetto User con la classe Greeter configurata correttamente dal contenitore, come mostrato nel codice seguente.

$container->setParameter('greeter.text', 'Hi'); 
$user = $container->get('user'); 
$user->name = "Jon"; 
$user->age = 20; 
$user->greet(); // Prints "Hi, Jon"

Abbiamo visto come configurare un oggetto in un container utilizzando lo stesso PHP. Symfony fornisce anche altri meccanismi. Sono file di configurazione XML e YAML. Vediamo come configurare un container utilizzando YAML. Per questo, installasymfony/config e symfony/yaml componenti insieme a symfony/dependency-injection componenti.

cd /path/to/dir 
mkdir dependency-injection-example 
cd dependency-injection-example 
composer require symfony/dependency-injection 
composer require symfony/config 
composer require symfony/yaml

La configurazione YAML verrà scritta in un file separato, services.yml. La configurazione YAML è composta da due sezioni,parameters e services. La sezione Parametri definisce tutti i parametri obbligatori. La sezione Servizi definisce tutti gli oggetti. La sezione Servizi è ulteriormente suddivisa in più sezioni, vale a dire,class, arguments, e calls. Class specifica la classe effettiva. Arguments specifica gli argomenti del costruttore. Infine, le chiamate specificano i metodi setter. È possibile fare riferimento a un'altra classe utilizzando il simbolo @, @greeter.

parameters: 
   greeter.text: 'Hello' 
services: 
   greeter: 
      class: Greeter
      arguments: ['%greeter.text%'] 
   user: 
      class: User 
      calls: 
         - [setGreeter, ['@greeter']]

Adesso, services.yml può essere caricato e configurato utilizzando FileLoader e YamlFileLoader come mostrato nel codice seguente.

use Symfony\Component\Config\FileLocator; 
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;  

$yamlContainer = new ContainerBuilder(); 
$loader = new YamlFileLoader($yamlContainer, new FileLocator(__DIR__)); 
$loader->load('services.yml');  

$yamlUser = $yamlContainer->get('user'); 
$yamlUser->name = "Jon"; 
$yamlUser->age = 25; 
$yamlUser->greet();

L'elenco completo del codice è il seguente.

main.php

<?php  
   require __DIR__ . '/vendor/autoload.php';  
   use Symfony\Component\DependencyInjection\ContainerBuilder; 
   use Symfony\Component\Config\FileLocator; 
   use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; 
   use Symfony\Component\DependencyInjection\Reference;  
   
   class Greeter { 
      private $greetingText; 
      
      public function __construct($greetingText) {
         $this->greetingText = $greetingText; 
      }  
      public function greet($name) { 
         echo $this->greetingText . ", " . $name . "\r\n"; 
      } 
   }  
   class User { 
      private $greeter;  
      public $name; 
      public $age;  
      
      public function setGreeter(\Greeter $greeter) { 
         $this->greeter = $greeter; 
      }  
      public function greet() { 
         $this->greeter->greet($this->name); 
      } 
   }  
   $container = new ContainerBuilder(); 
   $container 
      ->register('greeter', 'Greeter') 
      ->addArgument('%greeter.text%');  
   $container 
      ->register('user', 'User') 
      ->addMethodCall('setGreeter', array(new Reference('greeter')));
   
   $container->setParameter('greeter.text', 'Hi'); 
   $greeter = $container->get('greeter'); 
   $greeter->greet('Jon'); 
   
   $user = $container->get('user'); 
   $user->name = "Jon"; 
   $user->age = 20; 
   $user->greet();  
   
   $yamlContainer = new ContainerBuilder(); 
   $loader = new YamlFileLoader($yamlContainer, new FileLocator(__DIR__)); 
   $loader->load('services.yml');  

   $yamlHello = $yamlContainer->get('greeter'); 
   $yamlHello->greet('Jon'); 
   
   $yamlUser = $yamlContainer->get('user'); 
   $yamlUser->name = "Jon"; 
   $yamlUser->age = 25; 
   $yamlUser->greet();  
?>

services.yml

parameters: 
   greeter.text: 'Hello' 
services: 
   greeter: 
      class: Greeter 
      arguments: ['%greeter.text%'] 
   user: 
      class: User 
      calls: 
         - [setGreeter, ['@greeter']]

Il framework web di Symfony utilizza ampiamente il componente di inserimento delle dipendenze. Tutti i componenti sono vincolati dal contenitore di servizi centralizzato. Il framework web Symfony espone il contenitore in tutte le sueController attraverso containerproprietà. Possiamo ottenere tutti gli oggetti registrati in esso, ad esempio logger, mailer, ecc., Attraverso di esso.

$logger = $this->container->get('logger'); 
$logger->info('Hi');

Per trovare l'oggetto registrato nel contenitore, utilizzare il seguente comando.

cd /path/to/app 
php bin/console debug:container

Ci sono circa 200+ oggetti nel file hello web app creata nel capitolo installazione.