Bisher haben wir über einige grundlegende Konzepte gesprochen. Die Beispiele in den ersten beiden Artikeln sind für uns sehr hilfreich, um die Implementierung der Abhängigkeitsinjektion zu verstehen. Jetzt werden wir uns eingehend mit der Implementierung des Symfony 2-Dienstcontainers befassen.
Der Abhängigkeitsinjektionscontainer in Symfony wird von einer Klasse namens sfServiceContainer verwaltet.
Der Symfony-Container kann als unabhängige Komponente existieren. Das offizielle Subversion-Repository von Symfony kann heruntergeladen werden: http://svn .symfony-. project.com/components/dependency_injection/trunk/
. Es ist erwähnenswert, dass sich diese Komponente immer noch in einer kontinuierlichen iterativen Entwicklung befindet, sodass sie jederzeit aktualisiert werden kann (so hieß es 2009, aber jetzt scheint es damit aufgehört zu haben).
Gemäß der Designphilosophie von Symfony kann jeder Dienst ein Objekt sein, das von einem Container verwaltet wird. In dem im vorherigen Artikel vorgestellten Zend_Mail-Beispiel gibt es zwei Objekte: mailer und mail_transport
class Container { static protected $shared = array(); protected $parameters = array(); public function __construct(array $parameters = array()) { $this->parameters = $parameters; } public function getMailTransport() { return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array( 'auth' => 'login', 'username' => $this->parameters['mailer.username'], 'password' => $this->parameters['mailer.password'], 'ssl' => 'ssl', 'port' => 465, )); } public function getMailer() { if (isset(self::$shared['mailer'])) { return self::$shared['mailer']; } $class = $this->parameters['mailer.class']; $mailer = new $class(); $mailer->setDefaultTransport($this->getMailTransport()); return self::$shared['mailer'] = $mailer; } }
Wenn die Container-Klasse die sfServiceContainer-Klasse von Symfony erbt, kann der Code etwas einfacher gestaltet werden
class Container extends sfServiceContainer { static protected $shared = array(); protected function getMailTransportService() { return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array( 'auth' => 'login', 'username' => $this['mailer.username'], 'password' => $this['mailer.password'], 'ssl' => 'ssl', 'port' => 465, )); } protected function getMailerService() { if (isset(self::$shared['mailer'])) { return self::$shared['mailer']; } $class = $this['mailer.class']; $mailer = new $class(); $mailer->setDefaultTransport($this->getMailTransportService()); return self::$shared['mailer'] = $mailer; } }
Durch Beobachtung: Der Konstruktor- und Parameterkonfigurationsverwaltungscode wird weggelassen.
Aber das ist noch nicht alles. sfServiceContainer kann uns eine leistungsstarke und übersichtliche Schnittstelle bieten. Folgende Punkte sind bei der Verwendung der Schnittstelle zu beachten:
Der Name der Methode zum Abrufen des Dienstes muss angehängt werden Service. Normalerweise sind wir uns einig, dass der Name der Methode mit get beginnt und mit Service endet. Jeder Dienst verfügt über ein eindeutiges Logo. Das Logo ist normalerweise der Methodenname ohne Präfix und Suffix, getrennt durch Unterstriche. Wenn die Methode getMailTransportService() definiert ist, lautet der Dienstname mail_transport
2. Die Methode ist vom geschützten Typ, was bedeutet, dass Sie die Methode nicht direkt aufrufen können, um den Dienst zu erhalten. Wir werden später vorstellen, wie Container zum Abrufen von Diensten verwendet werden.
3. Auf den Container kann als Array zugegriffen werden, um die übergebenen Parameter zu erhalten. Zum Beispiel: $this[‘mailer.class’]
Die Dienstleistungsmarke muss eindeutig sein und darf nur aus Buchstaben, Zahlen, „_“ und „.“ bestehen. „.“ kann als Namespace verwendet werden (z. B. mail.mailer und mail.transport).
Jetzt wollen wir sehen, wie dieser neue Container verwendet wird
require_once 'PATH/TO/sf/lib/sfServiceContainerAutoloader.php'; sfServiceContainerAutoloader::register(); $sc = new Container(array( 'mailer.username' => 'foo', 'mailer.password' => 'bar', 'mailer.class' => 'Zend_Mail', )); $mailer = $sc->mailer;
Da die Container-Klasse sfServiceContainer erbt, wird die Schnittstelle sehr übersichtlich.
Der Zugriff auf den Dienst erfolgt über die einheitliche Schnittstelle
if ($sc->hasService('mailer')) { $mailer = $sc->getService('mailer'); } $sc->setService('mailer', $mailer);
Eine einfachere Möglichkeit besteht darin, auf den Dienst über Attribute zuzugreifen
if (isset($sc->mailer)) { $mailer = $sc->mailer; } $sc->mailer = $mailer;
if (!$sc->hasParameter('mailer_class')) { $sc->setParameter('mailer_class', 'Zend_Mail'); } echo $sc->getParameter('mailer_class'); // Override all parameters of the container $sc->setParameters($parameters); // Adds parameters $sc->addParameters($parameters);
Auf Parameter kann auch wie Arrays über Container zugegriffen werden
if (!isset($sc['mailer.class'])) { $sc['mailer.class'] = 'Zend_Mail'; } $mailerClass = $sc['mailer.class'];
Container können als Iteratoren zum Durchlaufen aller Dienste betrachtet werden
foreach ($sc as $id => $service) { echo sprintf("Service %s is an instance of %s.\n", $id, get_class($service)); }
Wenn nicht viele Dienste verwaltet werden müssen, Sie aber dennoch viel grundlegende Arbeit leisten und viel Code kopieren müssen, müssen Sie zugeben, dass Sie sfServiceContainer verwenden ist sehr nützlich.
Wenn die Anzahl der zu verwaltenden Dienste immer größer wird, muss es eine bessere Möglichkeit geben, die Dienste zu beschreiben.
Aus diesem Grund verwenden wir die sfServiceContainer-Klasse meistens nicht direkt. Dennoch ist es notwendig, einige Zeit damit zu verbringen, darüber zu sprechen, da es ein wichtiger Eckpfeiler des Dependency-Injection-Containers von Symfony ist.
Das Obige ist der Inhalt der PHP-Abhängigkeitsinjektionscontainerserie (3) Symfony. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (m.sbmmt.com).