Schlüsselpunkte
Dieser Artikel wurde von Thomas Punt überprüft. Vielen Dank an alle Peer -Rezensenten von SitePoint, um SitePoint -Inhalte in den Besten zu bringen!
Das Thema der asynchronen PHP -Programmierung wird fast jedes Treffen besprochen. Ich bin froh, dass es jetzt so oft erwähnt wird. Diese Redner enthüllten jedoch kein Geheimnis ...
Erstellen eines asynchronen Servers, Auflösungsnamen und Interaktion mit dem Dateisystem: Dies sind alles einfache Dinge. Es ist schwierig, eine eigene asynchrone Bibliothek zu erstellen. Und genau hier verbringst du die meiste Zeit!
Diese einfachen Dinge sind einfach, weil sie ein Beweis für das Konzept sind. Sie können sehen, wie ähnlich ihre frühen Schnittstellen waren:
var http = require("http"); var server = http.createServer(); server.on("request", function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello World"); }); server.listen(3000, "127.0.0.1");
Dieser Code wird mit Knoten 7.3.0
getestet
require "vendor/autoload.php"; $loop = React\EventLoop\Factory::create(); $socket = new React\Socket\Server($loop); $server = new React\Http\Server($socket); $server->on("request", function($request, $response) { $response->writeHead(200, [ "Content-Type" => "text/plain" ]); $response->end("Hello world"); }); $socket->listen(3000, "127.0.0.1"); $loop->run();
Dieser Code wird mit PHP 7.1 und React/HTTP getestet: 0.4.2
Heute werden wir einige Methoden betrachten, um Ihren Anwendungscode in einer asynchronen Architektur gut zu machen. Machen Sie sich keine Sorgen - Ihr Code kann immer noch in einer synchronen Architektur funktionieren, sodass Sie nichts aufgeben müssen, um diese neue Fähigkeit zu erlernen. Zusätzlich zu der Zeit verbringen Sie einige Zeit ...
auchSie finden den Code für dieses Tutorial auf GitHub. Ich habe es mit PHP 7.1 und den neuesten Versionen von ReactPHP und AMP getestet.
Hoffnungstheorie
Asynchroner Code hat einige gemeinsame Abstraktionen. Wir haben einen von ihnen gesehen: Rückrufe. Rückrufe, wie der Name schon sagt, beschreiben, wie sie mit langsamen oder blockierenden Vorgängen umgehen. Der Synchronisationscode ist voller Warten. Fragen Sie nach etwas und warten Sie, bis etwas passiert.
Daher können asynchrone Frameworks und Bibliotheken Rückrufe verwenden. Fordern Sie etwas an, wenn es passiert: Das Framework oder die Bibliothek ruft Ihren Code zurück.
Bei HTTP -Server werden wir nicht alle Anfragen präventiv verarbeiten. Wir werden auch nicht warten, bis die Anfrage stattfindet. Wir beschreiben nur den Code, der aufgerufen werden sollte, wenn die Anfrage auftritt. Die Veranstaltungsschleife kümmert sich um den Rest der Arbeit.
Die zweite gemeinsame Abstraktion ist vielversprechend. Rückrufe sind Hooks, die auf zukünftige Ereignisse warten, und Versprechen ist ein Hinweis auf zukünftige Werte. Sie sehen so aus:
var http = require("http"); var server = http.createServer(); server.on("request", function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello World"); }); server.listen(3000, "127.0.0.1");
Dies hat etwas mehr Code als nur Rückrufe zu verwenden, aber es ist eine interessante Möglichkeit, dies zu tun. Wir warten darauf, dass etwas passiert und dann einen anderen tun. Wenn etwas schief geht, werden wir den Fehler aufnehmen und vernünftig reagieren. Dies scheint einfach zu sein, wird aber nicht vollständig besprochen.
Wir verwenden immer noch Rückrufe, aber wir haben sie in eine Abstraktion eingewickelt, was uns auf andere Weise hilft. Ein Vorteil ist, dass sie mehrere Parsen -Rückrufe zulassen ...
require "vendor/autoload.php"; $loop = React\EventLoop\Factory::create(); $socket = new React\Socket\Server($loop); $server = new React\Http\Server($socket); $server->on("request", function($request, $response) { $response->writeHead(200, [ "Content-Type" => "text/plain" ]); $response->end("Hello world"); }); $socket->listen(3000, "127.0.0.1"); $loop->run();
Ich möchte, dass wir uns auf eine andere Sache konzentrieren. Das heißt, Promise bietet eine gemeinsame Sprache - eine gemeinsame Abstraktion - darüber nachzudenken, wie synchroner Code asynchroner Code wird.
Holen wir uns einen Anwendungscode und machen Sie ihn asynchron, verwenden Sie Versprechen ...
erstellen Sie PDF -Dateien
Es ist üblich, dass Anwendungen eine Art zusammenfassende Dokumente generieren - ob es sich um eine Rechnung oder eine Bestandsliste handelt. Angenommen, Sie haben eine E-Commerce-Anwendung, die Zahlungen über Stripe verarbeitet. Wenn ein Kunde einen Artikel kauft, möchten Sie, dass er eine PDF -Quittung für die Transaktion herunterladen kann.
Sie können dies auf verschiedene Arten tun, aber eine sehr einfache Weise ist es, das Dokument mit HTML und CSS zu generieren. Sie können es in ein PDF -Dokument umwandeln und den Kunden ermöglichen, es herunterzuladen.
Ich muss in letzter Zeit etwas Ähnliches tun. Ich fand, dass es nicht viele gute Bibliotheken gibt, die diesen Vorgang unterstützen. Ich kann keine einzige Abstraktion finden, mit der ich zwischen verschiedenen HTML → PDF -Motoren wechseln kann. Also fing ich selbst an, einen zu bauen.
Ich begann darüber nachzudenken, was meine Abstraktion tun musste. Ich habe eine sehr ähnliche Schnittstelle ausgewählt:
readFile() ->then(function(string $content) { print "content: " . $content; }) ->catch(function(Exception $e) { print "error: " . $e->getMessage(); });
$promise = readFile(); $promise->then(...)->catch(...); // ...让我们向现有代码添加日志记录 $promise->then(function(string $content) use ($logger) { $logger->info("file was read"); });
Ich werde nicht auf Details zur Verwendung von Dompdf eingehen. Ich denke, die Dokumentation wird gut genug gemacht, damit ich mich auf den asynchronen Teil dieser Implementierung konzentrieren kann.Wir werden später die Daten und parallele Methoden überprüfen. Das Wichtigste an dieser Treiberimplementierung ist, dass sie Daten (falls festgelegt, sonst der Standardwert) und benutzerdefinierte Optionen zusammenfasst. Es gibt diese an die Rückrufe weiter, die wir asynchron ausführen möchten.
dompdf ist keine asynchrone Bibliothek, es ist ein sehr langsamer Prozess, HTML in PDF zu konvertieren. Wie machen wir es asynchron? Nun, wir könnten einen vollständig asynchronen Konverter schreiben, oder wir könnten einen vorhandenen Synchronwandler verwenden.
Das habe ich für die parallele Methode getan:
var http = require("http"); var server = http.createServer(); server.on("request", function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello World"); }); server.listen(3000, "127.0.0.1");
Hier habe ich die Getter-Setter-Methode implementiert und dachte, ich könnte sie für die nächste Implementierung wiederverwenden. Die Datenmethode fungiert als Verknüpfung, um verschiedene Dokumentattribute in ein Array zu sammeln, was es einfacher macht, an anonyme Funktionen zu übergeben.
Parallele Methode beginnt interessant zu werden:
require "vendor/autoload.php"; $loop = React\EventLoop\Factory::create(); $socket = new React\Socket\Server($loop); $server = new React\Http\Server($socket); $server->on("request", function($request, $response) { $response->writeHead(200, [ "Content-Type" => "text/plain" ]); $response->end("Hello world"); }); $socket->listen(3000, "127.0.0.1"); $loop->run();
Ich mag das AMP -Projekt wirklich. Es handelt sich um eine Sammlung von Bibliotheken, die asynchrone Architekturen unterstützen, und sie sind wichtige Befürworter des Async-Interop-Projekts.
Eine ihrer Bibliotheken wird als Amphp/Parallel bezeichnet, das Multi-Thread- und Multi-Process-Code unterstützt (erweitert über PThreads und Prozesskontrolle). Diese Spawn -Methoden geben die Implementierung von AMPs Versprechen zurück. Dies bedeutet, dass die Render -Methode wie jede andere Methode verwendet werden kann, die ein Versprechen zurückgibt:
readFile() ->then(function(string $content) { print "content: " . $content; }) ->catch(function(Exception $e) { print "error: " . $e->getMessage(); });
Dieser Code ist etwas kompliziert. AMP bietet außerdem eine Implementierung von Ereignisschleifen und allen Hilfscode, um einen normalen PHP -Generator in Coroutinen und Versprechen umzuwandeln. Sie können in einem anderen Beitrag lesen. Ich habe geschrieben, wie dies überhaupt möglich ist und wie es sich auf den PHP -Generator bezieht.
Das zurückgegebene Versprechen wird ebenfalls standardisiert. AMP gibt die Implementierung der Versprechenspezifikation zurück. Es unterscheidet sich geringfügig von dem oben gezeigten Code, führt aber dennoch dieselbe Funktion aus.
Der Generator arbeitet wie eine Coroutine in einer Sprache mit Coroutinen. Coroutinen sind Funktionen, die unterbrochen werden können, dh sie können verwendet werden, um kurzfristige Operationen auszuführen, und dann innehalten, während sie auf etwas warten. Während der Pause können andere Funktionen Systemressourcen verwenden.
eigentlich sieht das so aus:
$promise = readFile(); $promise->then(...)->catch(...); // ...让我们向现有代码添加日志记录 $promise->then(function(string $content) use ($logger) { $logger->info("file was read"); });
Dies scheint viel komplizierter zu sein, als zu Beginn nur Synchroncode zu schreiben. Aber was es zulässt, ist, dass etwas anderes passieren kann, wenn wir darauf warten, dass FuncreturnSpromise abgeschlossen ist.
Versprechen generieren ist genau das, was wir Abstraktion nennen. Es bietet uns einen Rahmen, durch den wir Funktionen erstellen können, die das Versprechen zurückgeben. Der Code kann auf vorhersehbare und verständliche Weise mit diesen Versprechen interagieren.
Sehen Sie sich an, wie es aussieht, PDF -Dokumente mit unserem Treiber zu rendern:
interface Driver { public function html($html = null); public function size($size = null); public function orientation($orientation = null); public function dpi($dpi = null); public function render(); }
Dies ist nicht so nützlich wie das Generieren von PDFs auf einem asynchronen HTTP -Server. Es gibt eine AMP -Bibliothek namens Aerys, die das Erstellen dieser Art von Servern erleichtert. Mit Aerys können Sie den folgenden HTTP -Servercode erstellen:
class DomDriver extends BaseDriver implements Driver { private $options; public function __construct(array $options = []) { $this->options = $options; } public function render() { $data = $this->data(); $custom = $this->options; return $this->parallel( function() use ($data, $custom) { $options = new Options(); $options->set( "isJavascriptEnabled", true ); $options->set( "isHtml5ParserEnabled", true ); $options->set("dpi", $data["dpi"]); foreach ($custom as $key => $value) { $options->set($key, $value); } $engine = new Dompdf($options); $engine->setPaper( $data["size"], $data["orientation"] ); $engine->loadHtml($data["html"]); $engine->render(); return $engine->output(); } ); } }
In ähnlicher Weise werde ich jetzt nicht im Detail in Aerys eingehen. Dies ist eine beeindruckende Software, die es wert ist, einen eigenen Artikel zu haben. Sie müssen nicht verstehen, wie Aerys arbeitet, um zu sehen, wie natürlich unser Konvertercode daneben aussieht.
Mein Chef sagte: "Verwenden Sie nicht asynchron!"
Wenn Sie nicht sicher sind, wie lange es dauern wird, eine asynchrone Anwendung zu erstellen, warum dauert es dann so viel Mühe? Das Schreiben dieses Code ermöglicht es uns, Einblick in neue Programmierparadigmen zu erhalten. Und nur weil wir diesen Code asynchron schreiben, heißt das nicht, dass er nicht in einer synchronen Umgebung funktioniert.
Um diesen Code in einer synchronen Anwendung zu verwenden, müssen wir nur einen asynchronen Code innerhalb von:
verschiebenabstract class BaseDriver implements Driver { protected $html = ""; protected $size = "A4"; protected $orientation = "portrait"; protected $dpi = 300; public function html($body = null) { return $this->access("html", $html); } private function access($key, $value = null) { if (is_null($value)) { return $this->$key; } $this->$key = $value; return $this; } public function size($size = null) { return $this->access("size", $size); } public function orientation($orientation = null) { return $this->access("orientation", $orientation); } public function dpi($dpi = null) { return $this->access("dpi", $dpi); } protected function data() { return [ "html" => $html, "size" => $this->size, "orientation" => $this->orientation, "dpi" => $this->dpi, ]; } protected function parallel(Closure $deferred) { // TODO } }
Mit diesem Dekorator können wir Code schreiben, der wie ein synchroner Code aussieht:
var http = require("http"); var server = http.createServer(); server.on("request", function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello World"); }); server.listen(3000, "127.0.0.1");
Es wird der Code immer noch asynchron ausgeführt (zumindest im Hintergrund), aber all dies ist dem Verbraucher nicht ausgesetzt. Sie können es in einer Synchronisierungsanwendung verwenden und werden nie wissen, was hinter den Kulissen vor sich geht.
Unterstützung anderer Frameworks
Amp hat einige spezifische Anforderungen, die es für alle Umgebungen ungeeignet machen. Beispielsweise erfordert die Basic AMP (Event Loop) -Bibliothek PHP 7.0. Die parallele Bibliothek erfordert eine PTHREADS -Erweiterung oder eine Verlängerung der Prozesssteuerung.
Ich möchte diese Einschränkungen nicht jedem auferlegen und möchte wissen, wie ich ein breiteres System unterstützen kann. Die Antwort besteht
require "vendor/autoload.php"; $loop = React\EventLoop\Factory::create(); $socket = new React\Socket\Server($loop); $server = new React\Http\Server($socket); $server->on("request", function($request, $response) { $response->writeHead(200, [ "Content-Type" => "text/plain" ]); $response->end("Hello world"); }); $socket->listen(3000, "127.0.0.1"); $loop->run();
readFile() ->then(function(string $content) { print "content: " . $content; }) ->catch(function(Exception $e) { print "error: " . $e->getMessage(); });
Ich bin es gewohnt, Schließungen an Multi-Threaded- und Multi-Process-Arbeiter weiterzugeben, denn so funktionieren Phreads und Prozesskontrolle. Die Verwendung von ReactPHP-Prozessobjekten ist völlig unterschiedlich, da sie für die Ausführung von Multi-Process auf Exec angewiesen sind. Ich habe mich entschlossen, die gleiche Schließfunktion zu implementieren, die ich gewohnt bin. Dies ist für asynchrone Code nicht erforderlich - es ist nur eine Frage des Geschmacks.Superclosure -Bibliothek serialisiert Verschlüsse und ihre gebundenen Variablen. Der größte Teil des Codes hier ist der Code, den Sie im Worker -Skript erwarten. Tatsächlich besteht die einzige Möglichkeit, ReactPhps untergeordnete Prozessbibliothek (neben der Serialisierung von Schließungen) zu verwenden, um Aufgaben an Arbeiterskripte zu senden.
Jetzt laden wir unsere Treiber nicht mehr mit $ this- & gt; parallel und ampspezifisch, sondern können die Run-Programmimplementierung übergeben. Als asynchronisiertes Code ähnelt dies:
$promise = readFile(); $promise->then(...)->catch(...); // ...让我们向现有代码添加日志记录 $promise->then(function(string $content) use ($logger) { $logger->info("file was read"); });
Seien Sie nicht schockiert über den Unterschied zwischen ReactPHP -Code und AMP -Code. ReactPHP implementiert nicht die gleiche Coroutine -Basis wie AMP. Stattdessen bevorzugt ReactPHP es, Rückrufe zu verwenden, um die meisten Dinge zu bewältigen. Dieser Code führt immer noch die PDF -Konvertierung parallel aus und gibt die generierten PDF -Daten zurück.Wenn wir das Programm in Zusammenfassung ausführen, können wir alle gewünschten asynchronen Framework verwenden, und wir können erwarten, dass der Treiber die Abstraktion dieses Frameworks zurückgibt.
Kann ich das verwenden?
Anfangs war es nur ein Experiment, und es wurde eine HTML → PDF -Bibliothek mit mehreren Treibern und mehreren Laufprogrammen. Es ist wie das Flysystem -Äquivalent von HTML → PDF, aber es ist auch ein großartiges Beispiel dafür, wie man eine asynchrone Bibliothek schreibt.Wenn Sie versuchen, eine asynchrone PHP -Anwendung zu erstellen, finden Sie Lücken im Bibliotheksökosystem. Lassen Sie sich nicht von diesen einschüchtern! Nutzen Sie stattdessen die Gelegenheit, darüber nachzudenken, wie Sie die von ReactPHP und AMP bereitgestellten Abstraktionen verwenden, um Ihre eigenen asynchronen Bibliotheken zu erstellen.
Haben Sie in letzter Zeit eine interessante asynchrone PHP -Anwendung oder -bibliothek erstellt? Bitte lassen Sie es uns in den Kommentaren wissen.
FAQ auf asynchronem Konvertieren von HTML in PDF
asynchrones Programmieren spielt eine entscheidende Rolle bei der Umwandlung von HTML in PDF. Es ermöglicht nicht blockierende Vorgänge, was bedeutet, dass die Engine im Hintergrund ausgeführt wird, sodass der Rest Ihres Codes die Ausführung fortsetzen kann, wenn der asynchrone Betrieb abgeschlossen ist. Dies führt zu einer effizienteren Nutzung von Ressourcen und einer verbesserten Leistung, insbesondere in Anwendungen, die eine große Anzahl von E/A -Operationen betreffen, z. B. die Konvertierung von HTML in PDF.
reactPhp ist eine Bibliothek mit niedriger Ebene für ereignisgesteuerte Programmierung in PHP. Es bietet die Kerninfrastruktur für die Erstellung asynchroner Bibliotheken in PHP. Mit ReactPHP können Sie nicht blockierende Code mit der bekannten Syntax von PHP schreiben, um leichte Leistungsanwendungen zu erstellen.
Der Prozess der asynchronen Umwandlung von HTML in PDF umfasst mehrere Schritte. Zunächst müssen Sie eine HTML -Vorlage einrichten, die die Struktur und den Inhalt des PDF definiert. Als nächstes verwenden Sie asynchrone Bibliotheken wie ReactPHP, um den Konvertierungsprozess zu verarbeiten. Dies beinhaltet das Lesen der HTML -Datei, das Konvertieren in ein PDF und das Speichern der generierten PDF -Datei. Die asynchrone Natur dieses Prozesses bedeutet, dass Ihre Anwendung weiterhin andere Aufgaben ausführen kann, während die Transformation im Gange ist.
Ja, Sie können in anderen Sprachen asynchron programmieren. Zum Beispiel ist Node.js aufgrund seiner ereignisgesteuerten Architektur eine beliebte Wahl für den Aufbau asynchroner Anwendungen. Wenn Sie jedoch bereits mit PHP vertraut sind, können Sie Bibliotheken wie ReactPHP problemlos von der asynchronen Programmierung nutzen, ohne neue Sprachen lernen zu müssen.
Fehlerbehebung ist ein wichtiger Aspekt der asynchronen Programmierung. In ReactPHP können Sie Fehler behandeln, indem Sie einen Fehlerereignishandler an ein Versprechensobjekt anfügen. Wenn während des Konvertierungsprozesses ein Fehler auftritt, wird dieser Handler aufgerufen, sodass Sie den Fehler protokollieren oder andere entsprechende Aktionen ausführen können.
Es gibt viele Vorteile, um HTML in PDF umzuwandeln. Sie können eine statische, tragbare Version einer Webseite erstellen, die leicht offline, gedruckt oder freigegeben werden kann. Das PDF behält auch das Format und das Layout des ursprünglichen HTML bei, um sicherzustellen, dass der Inhalt unabhängig vom Gerät oder der Plattform gleich aussieht.
Es gibt verschiedene Möglichkeiten, die Leistung einer asynchronen PHP -Anwendung zu optimieren. Ein Ansatz besteht darin, Bibliotheken wie ReactPHP zu verwenden, die eine Schnittstelle auf niedriger Ebene für die ereignisgesteuerte Programmierung liefert. Auf diese Weise können Sie nicht blockierende Code schreiben, wodurch die Leistung von I/O-intensiven Operationen wie das Konvertieren von HTML in PDF erheblich verbessern kann.
Ja, HTML kann synchron in PDF konvertiert werden. Dieser Ansatz kann jedoch die Ausführung Ihrer Anwendung blockieren, bis der Konvertierungsprozess abgeschlossen ist, was zu Leistungsproblemen für E/O-intensive Anwendungen führen kann. Andererseits ermöglicht eine asynchrone Konvertierung Ihre Anwendung weiterhin andere Aufgaben, während die Konvertierung im Gange ist, was zu einer besseren Leistung und Ressourcenauslastung führt.
asynchrone Programmierung in PHP kann aufgrund der Synchronisationseigenschaften von PHP eine Herausforderung sein. Bibliotheken wie ReactPHP bieten jedoch die Architektur, die zum Schreiben von nicht blockierenden Code in PHP erforderlich ist. Das Verständnis ereignisgesteuerter Programmiermodelle und das Beherrschen der Verwendung von Versprechen kann ebenfalls eine Herausforderung sein, sind jedoch der Schlüssel zur Nutzung der Vorteile der asynchronen Programmierung.
Testen der Leistung einer asynchronen PHP -Anwendung umfasst die Messung der Schlüsselmetriken unter verschiedenen Lastbedingungen wie Reaktionszeit, Speicherverbrauch und CPU -Nutzung. Tools wie Apache JMeter oder Belagerung können verwendet werden, um die Last einer Anwendung zu simulieren und Leistungsdaten zu sammeln. Darüber hinaus können Analyse -Tools wie XDEBUG Ihnen dabei helfen, Engpässe in Ihrem Code zu identifizieren und ihre Leistung zu optimieren.
Das obige ist der detaillierte Inhalt vonSchreiben asynchrischer Bibliotheken - Lassen Sie HTML in PDF konvertieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!