Dieser Artikel stellt hauptsächlich die Analyse des laufenden Prozesses des PHP-Containers Pimple vor, der einen gewissen Referenzwert hat. Jetzt kann ich ihn mit allen teilen, die ihn brauchen.
Abschlüsse und anonyme Funktionen wurden in PHP5.3.0 eingeführt.
Ein Abschluss bezieht sich auf eine Funktion, die beim Erstellen den umgebenden Zustand kapselt. Auch wenn die Umgebung, in der sich der Verschluss befindet, nicht mehr existiert, ist der im Verschluss eingekapselte Zustand weiterhin vorhanden.
Theoretisch sind Abschlüsse und anonyme Funktionen unterschiedliche Konzepte. Aber PHP behandelt es als dasselbe Konzept.
Tatsächlich sind Abschlüsse und anonyme Funktionen als Funktionen getarnte Objekte. Sie sind Instanzen der Closure-Klasse.
Abschlüsse sind wie Strings und Ganzzahlen erstklassige Werttypen.
Abschluss erstellen:
<?php $closure = function ($name) { return 'Hello ' . $name; }; echo $closure('nesfo');//Hello nesfo var_dump(method_exists($closure, '__invoke'));//true
Der Grund, warum wir die Variable$closure
aufrufen können, liegt darin, dass der Wert dieser Variablen ein Abschluss ist und das Abschlussobjekt die magische Methode__invoke()
implementiert. Solange nach dem Variablennamen ein()
steht, findet PHP die Methode__invoke()
und ruft sie auf.
Normalerweise werden PHP-Abschlüsse als Rückrufe von Funktionen verwendet.
array_map()
, preg_replace_callback()
Methoden verwenden alle Rückruffunktionen. Dies ist der beste Zeitpunkt, um Abschlüsse zu verwenden!
Zum Beispiel:
<?php $numbersPlusOne = array_map(function ($number) { return $number + 1; }, [1, 2, 3]); print_r($numbersPlusOne);
Ruft das Ergebnis ab:
[2, 3, 4]
Vor Schließungen konnten Sie benannte Funktionen nur einzeln erstellen und diese Funktion dann namentlich referenzieren. Dadurch wird die Codeausführung etwas langsamer und die Implementierung des Rückrufs wird vom Nutzungsszenario isoliert.
<?php function incrementNum ($number) { return $number + 1; } $numbersPlusOne = array_map('incrementNum', [1, 2, 3]); print_r($numbersPlusOne);
implementiert die ArrayAccess-Schnittstelle, die es Objekten ermöglicht, wie Arrays zu funktionieren. Die ArrayAccess-Schnittstelle enthält vier Methoden, die implementiert werden müssen:
interface ArrayAccess { //检查一个偏移位置是否存在 public mixed offsetExists ( mixed $offset ); //获取一个偏移位置的值 public mixed offsetGet( mixed $offset ); //设置一个偏移位置的值 public mixed offsetSet ( mixed $offset ); //复位一个偏移位置的值 public mixed offsetUnset ( mixed $offset ); }
Die SplObjectStorage-Klasse implementiert eine Map mit Objekten als Schlüssel oder eine Sammlung von Objekten (wenn das Objekt als Schlüssel ignoriert wird). ) diese Datenstruktur. Eine Instanz dieser Klasse ähnelt einem Array, die darin gespeicherten Objekte sind jedoch alle eindeutig. Ein weiteres Merkmal dieser Klasse besteht darin, dass Sie das angegebene Objekt direkt daraus löschen können, ohne die gesamte Sammlung durchlaufen oder durchsuchen zu müssen.
::class
Syntax Weil ::class
eine Zeichenfolge darstellt. Der Vorteil der Verwendung von ::class
besteht darin, dass Sie eine Klasse direkt in der IDE umbenennen können und die IDE dann automatisch die zugehörigen Referenzen verarbeitet.
Wenn PHP den relevanten Code ausführt, wird gleichzeitig nicht zuerst die entsprechende Klasse geladen.
In ähnlicher Weise kann die automatisierte Code-Inspektion auch Klassen korrekt identifizieren.
Pimpl ist ein beliebter Container in der PHP-Community. Es gibt nicht viel Code, siehe https://github.com/silexphp/P... für Details.
Unsere Anwendung kann basierend auf Pimple entwickelt werden:
namespace EasyWeChat\Foundation; use Pimple\Container; class Application extends Container { /** * Service Providers. * * @var array */ protected $providers = [ ServiceProviders\ServerServiceProvider::class, ServiceProviders\UserServiceProvider::class ]; /** * Application constructor. * * @param array $config */ public function __construct($config) { parent::__construct(); $this['config'] = function () use ($config) { return new Config($config); }; if ($this['config']['debug']) { error_reporting(E_ALL); } $this->registerProviders(); } /** * Add a provider. * * @param string $provider * * @return Application */ public function addProvider($provider) { array_push($this->providers, $provider); return $this; } /** * Set providers. * * @param array $providers */ public function setProviders(array $providers) { $this->providers = []; foreach ($providers as $provider) { $this->addProvider($provider); } } /** * Return all providers. * * @return array */ public function getProviders() { return $this->providers; } /** * Magic get access. * * @param string $id * * @return mixed */ public function __get($id) { return $this->offsetGet($id); } /** * Magic set access. * * @param string $id * @param mixed $value */ public function __set($id, $value) { $this->offsetSet($id, $value); } }
So verwenden Sie unsere Anwendung:
$app = new Application([]); $user = $app->user;
Danach können wir die Methoden des $user
-Objekts verwenden. Wir haben festgestellt, dass es kein $this->user
-Attribut gibt, es aber direkt verwendet werden kann. Hauptsächlich die Rolle dieser beiden Methoden:
public function offsetSet($id, $value){} public function offsetGet($id){}
Im Folgenden erklären wir, was Pimple tut, wenn es diese beiden Codezeilen ausführt. Aber bevor wir dies erklären, werfen wir einen Blick auf einige Kernkonzepte von Containern.
Dienstanbieter ist die Brücke zwischen dem Container und der spezifischen Funktionsimplementierungsklasse. Dienstanbieter müssen Schnittstellen-ServiceProviderInterface
implementieren:
namespace Pimple; /** * Pimple service provider interface. * * @author Fabien Potencier * @author Dominik Zogg */ interface ServiceProviderInterface { /** * Registers services on the given container. * * This method should only be used to configure services and parameters. * It should not get services. * * @param Container $pimple A container instance */ public function register(Container $pimple); }
Alle Dienstanbieter müssen Schnittstellen-register
-Methoden implementieren.
In unserer Anwendung gibt es standardmäßig zwei Dienstanbieter:
protected $providers = [ ServiceProviders\ServerServiceProvider::class, ServiceProviders\UserServiceProvider::class ];
Am Beispiel von UserServiceProvider schauen wir uns die Code-Implementierung an:
namespace EasyWeChat\Foundation\ServiceProviders; use EasyWeChat\User\User; use Pimple\Container; use Pimple\ServiceProviderInterface; /** * Class UserServiceProvider. */ class UserServiceProvider implements ServiceProviderInterface { /** * Registers services on the given container. * * This method should only be used to configure services and parameters. * It should not get services. * * @param Container $pimple A container instance */ public function register(Container $pimple) { $pimple['user'] = function ($pimple) { return new User($pimple['access_token']); }; } }
Wir sehen, dass dieser Dienst Folgendes bietet Die Registrierungsmethode des Benutzers fügt dem Container Attribute user
hinzu, aber was zurückgegeben wird, ist kein Objekt, sondern ein Abschluss. Ich werde das später erklären.
Wir verwenden $this->registerProviders();
, um alle Dienstanbieter im Konstruktor der Anwendung zu registrieren:
private function registerProviders() { foreach ($this->providers as $provider) { $this->register(new $provider()); } }
Bei genauerem Hinsehen stellen wir fest, dass es hier einen instanziierten Dienstanbieter gibt , und rief die register
-Methode des Containers Pimple auf:
public function register(ServiceProviderInterface $provider, array $values = array()) { $provider->register($this); foreach ($values as $key => $value) { $this[$key] = $value; } return $this; }
Und hier wurde die register
-Methode des Dienstanbieters aufgerufen, was wir im vorherigen Abschnitt erwähnt haben: Die Registrierungsmethode gibt den Container fügt das Attribut user
hinzu, gibt aber kein Objekt, sondern einen Abschluss zurück.
Wenn wir Attribute user
zum Container Pimple hinzufügen, wird die Methode offsetSet($id, $value)
aufgerufen: Weisen Sie den Attributen values
und keys
des Containers Pimple jeweils Werte zu:
$this->values[$id] = $value; $this->keys[$id] = true;
Gehen Sie hierher, wir haben nicht die Klasse EasyWeChatUserUsr
instanziiert, die tatsächlich die eigentliche Funktionalität bereitstellt. Die Registrierung des Dienstleisters ist jedoch abgeschlossen.
Wenn wir hier ausführen:
$user = $app->user;
ruft offsetGet($id)
auf und instanziiert die echte Klasse:
$raw = $this->values[$id]; $val = $this->values[$id] = $raw($this); $this->raw[$id] = $raw; $this->frozen[$id] = true; return $val;
$raw
erhält den Abschluss:
$pimple['user'] = function ($pimple) { return new User($pimple['access_token']); };
$raw($this)
gibt das instanziierte Objekt User zurück. Das heißt, nur der tatsächliche Aufruf instanziiert die spezifische Klasse. Später können wir Methoden in der User-Klasse über $this['user']
oder $this->user
aufrufen.
Natürlich gibt es in Pimple viele Funktionen, die eine eingehende Untersuchung wert sind, daher werden wir sie hier nicht zu ausführlich erläutern.
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er für das Studium aller hilfreich ist. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website.
Verwandte Empfehlungen:
Wie WordPress die Funktion wp_head() verwendet
Geltungsbereich, global, statisch von PHP-Variablen Warten für Schlüsselwörter
Das obige ist der detaillierte Inhalt vonAnalyse des laufenden Prozesses des PHP-Containers Pimple. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!