PHP/Tutorials/Einführung in die Interna/Grundlegender Aufbau von PHP

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Allgemeines

PHP als Sprache besteht aus verschiedenen Teilen, die verschiedene Aufgaben übernehmen. Das folgende Diagramm zeigt den Aufbau von PHP:

Artikel-PHP--Einführung in die Interna--php-allgemeiner-aufbau.png

Das zentrale Element von PHP ist die sogenannte Zend-Engine. Diese ist für das Kompilieren und Ausführen von PHP-Scripten verantwortlich. Außerdem stellt sie die nötigen Schnittstellen für den Rest von PHP zur Verfügung. Damit PHP mit dem Webserver kommunizieren kann, gibt es sogenannte SAPIs (Server APIs). Dieses modulare Konzept ermöglicht es, dass man PHP mit verschiedenen Webservern verwenden kann. Jede SAPI stellt Methoden zur Verfügung, um Informationen über die aktuelle Ausführungsumgebung (HTTP-Request-Typ, POST-Daten, URL-Parameter, usw.) zu gewinnen und andere Methoden, um an den Webserver Statuscodes, Header und Antwortdaten zu schicken. Einige SAPIs stellen ferner auch noch einige zusätzliche Methoden zur Verfügung, um direkt aus PHP heraus mit dem Webserver interagieren zu können. Die bekanntesten SAPIs sind CGI (für den Betrieb als CGI- oder FastCGI-Interpreter), CLI (für Kommandozeilenanwendungen), Embed (für das Einbetten von PHP in beliebigen Anwendungen), Apache2 (für die Verwendung von PHP als Apache-Modul) und ISAPI (für die Verwendung von PHP als IIS-Modul).

Auf der Zend-Engine und den SAPIs aufbauend bietet PHP eine Standard-API an, die Erweiterungen nutzen können. Diese beinhaltet einige nützliche Funktionen sowie definiert auf C-Ebene einige Makros neu, damit aus Kompatibilitätsgründen zu PHP 4 von der Zend-Engine etwas abstrahiert wird.

Als weitere auf der Zend-Engine aufbauendes, zentral verfügbares API sind die sogenannten Streams. Sie bieten eine einheitliche Schnittstelle, um Dateien, Netzwerksocksets und ähnliches kapseln zu können. Die eigentliche Implementierung für beispielsweise den Zugriff auf Dateien, auf Netzwerksockets oder auf HTTP-Resourcen wird hier von PHP-Erweiterungen übernommen, die Streams-Schnittstelle selbst ist nur das Framework hierfür.

PHP-Erweiterungen stellen hingegen Funktionalität bereit, die in PHP selbst zur Verfügung steht. So sind fast alle Funktionen und Klassen, die in PHP vordefiniert sind, in Erweiterungen implementiert, die immer aktiv sind – wie z. B. standard oder math. Es gibt nur ganz wenige Funktionen, die von der Zend-Engine selbst bereitgestellt werden.

Diese Struktur von PHP findet sich auch im Dateisystemlayout des PHP-Quellcodes wieder: Dort gibt es verschiedene Unterverzeichnisse, die die jeweiligen Teile beherbergen. Im folgenden ist eine Auflistung der wichtigsten Unterverzeichnisse des PHP-Quellcodes und ihrer Korrespondenz zu den einzelnen dargestellten Teilen:
Unterverzeichnis Erläuterung
TSRM Enthält den Thread safe resource manager, der für das Threading verantwortlich ist (siehe nächster Abschnitt)
Zend Enthält die Zend-Engine
sapi Enthält die verschiedenen SAPIs (jedes SAPI ein eigenes Unterverzeichnis davon, z. B. sapi/cgi für das CGI-SAPI)
main Enthält das Standard-PHP-API sowie einige Hilfsfunktionen für die meisten SAPIs
main/streams Enthält das Streams-Framework
ext Enthält alle mit PHP gebündelten Erweiterungen
win32, netware Enthält spezifische Code-Teile für Windows und Novell Netware

Im folgenden wird nun ein grober Überblick über die Funktionalität der einzelnen Teile beschrieben, die dann auf einzelnen Seiten näher behandelt werden.

Threading-Modell

PHP selbst ist threadsicher geschrieben. Das heißt: Wenn man PHP von verschiedenen Threads aus aufruft, kommt es sich nicht gegenseitig in die Quere. Allerdings gibt es viele PHP-Erweiterungen, die Bibliotheken verwenden, die selbst nicht threadsicher sind. Aus diesem Grund wird heute immer noch davon abgeraten, PHP in einem gethreadeten Webserver zu verwenden.

Im Gegensatz zu anderen Programmiersprachen, die mehrere Threads auch innerhalb der Programmiersprache unterstützen, verfolgt PHP ein anderes Konzept: Jeder Thread ist unabhängig voneinander und aus der Sprache selbst hat keinerlei Zugriff auf Threads. Verschiedene PHP-Instanzen im gleichen Prozess werden also vollständig voneinander abgeschottet.

Damit dies funktioniert wurde der Thread safe resource manager (TSRM) entwickelt. Er abstrahiert von auf verschiedenen Plattformen vorhandenen Thread-Implementierungen und stellt portable Möglichkeiten zur Verfügung, Thread-globale Variablen zu definieren, die jedoch keinen Effekt auf andere Threads haben. Er stellt ferner Funktionen zur Verfügung, mit denen man Informationen über die Thread-Umgebung erhalten kann (z. B. die Id des aktuellen Threads) und definiert einige C-Makros, die für die Thread-Sicherheit wichtig sind.

Die Zend-Engine

Die Zend-Engine ist das eigentliche Herzstück von PHP. Sie ist es, die PHP-Code zur Ausführung bringt und alle elementaren Bestandteile der Sprache zur Verfügung stellt.

Die wichtigsten Dinge, die die Zend-Engine zur Verfügung stellt sind die folgenden:

  • Threadsichere Speicherverwaltung, die es außerdem noch erlaubt, Speicher eines Scripts am Ende komplett wieder freizugeben unabhängig von eventuellen Speicherlecks im Code.
  • Einen Compiler, der PHP-Code in eine besondere Form von Bytecode übersetzt.
  • Eine Ausführungsschicht, die sich darum kümmert, dass diese Form des Bytecodes ausgeführt werden kann
  • Datenstrukturen, um Werte von PHP-Variablen darzustellen
  • Ein Objektmodell für die Umsetzung von OOP in PHP

In den folgenden Seiten wird ausführlich auf verschiedene Aspekte dieser Teile eingegangen werden.

Webserver-Integration und SAPIs

PHP ist in Bezug auf verschiedene Webserver modular aufgebaut. Man kann die Schicht, die mit dem Webserver kommuniziert, austauschen und damit PHP in beliebige Webserver integrieren.

Am bekanntesten sind die SAPIs CGI, CLI und Apache. Bei CGI verhält sich PHP wie ein normales CGI-Programm, das die Anfrage per Umgebungsvariablen und Standardeingabe nach dem CGI-Standard entgegennimmt und die Antwort über die Standardausgabe wieder an den Webserver zurückschickt. Das Apache-SAPI (eigentlich gibt es zwei davon: für Apache 1 und für Apache 2) dagegen integriert sich als Modul in den Apache-Webserver. Beim CLI-SAPI dagegen geht es nicht um Webserver-Integration sondern um die Möglichkeit, PHP von der Kommandozeile aus verwenden zu können – als Allzwecksprache und nicht nur im Web.

Ein SAPI muss folgendes bereitstellen:

  • Funktionen zum Erfragen von Informationen des Requests (HTTP-Header, Cookies, POST-Daten, usw.)
  • Funktionen zur Ausgabe der Antwort (Senden von HTTP-Headern, Ausgeben des Antwort-Inhalts, usw.)
  • Funktionen die aufgerufen werden, damit die superglobalen Variablen befüllt werden können
  • Funktionen zum Loggen von Fehlern

Auf einer eigenen Seite wird die Funktionsweise des CGI-SAPIs erläutert werden.

Streams für Dateien und Netzwerksockets

Streams bieten in PHP eine Abstraktionsschicht für den Zugriff auf Dateien, Netzwerksockets, HTTP-Ressourcen und vieles mehr. Folgendes Diagramm verdeutlicht die Struktur der Streams-Implementierung in PHP:

Artikel-PHP--Einführung in die Interna--php-streams-aufbau.png

Um Zugriff auf eine Datei, eine HTTP-Ressource oder auf ein Netzwerksocket zu erlangen genügt es, wenn man in PHP lediglich das Streams-API anspricht. Es stellt Funktionen zum Öffnen dieser Ressourcen, zum Lesen, zum Schreiben, zum Ändern des Positionszeigers, zum Sperren (Locking) und vieles mehr zur Verfügung. Die eigentliche Implementierung erfolgt in verschiedenen Backends, die dann für die eigentliche Kommunikation mit dem Betriebssystem oder mit anderen Bibliotheken sorgen. Es gibt zwei Arten von Backends:

Wrapper:

Diese Backends implementieren eine eigentliche Funktionalität der Streams, d. h. sie bieten das Interface mit dem Betriebssystem, um Dateien zu lesen oder um über Netzwerksockets zu kommunizieren.

Filter:

Diese Backends klinken sich in einen Datenstrom ein und manipulieren diesen. Zum Beispiel gibt es Kompressionsfilter, mit denen man komprimierte Dateien on-the-fly lesen oder schreiben kann, ohne sich selbst um die Kompression kümmern zu müssen.

Im PHP-Kern selbst ist keinerlei Wrapper oder Filter für Streams vorab implementiert – diese sind alle in verschiedenen PHP-Erweiterungen enthalten. Allerdings: Die Wrapper für Dateisystem-, Netzwerksocket- und HTTP/FTP-Zugriff sind in der PHP-Erweiterung standard implementiert, die nicht deaktiviert werden kann. Insofern steht eine gewisse Mindestfunktionalität immer in PHP zur Verfügung.

Das Streams-API stellt auch Funktionalität zur Verfügung, in der man in PHP selbst eigene Wrapper und Filter implementieren kann. Damit sind Streams in PHP eine sehr erweiterbare Abstraktionsschicht.

Erweiterungen

Erweiterungen in PHP teilt man in zwei Kategorien ein:

Normale Erweiterungen:

Hier werden zusätzliche Funktionen, Konstanten und/oder Klassen zur Verfügung gestellt, die von PHP-Scripten aus genutzt werden können. Oftmals sind diese Funktionen/Klassen Interfaces zu C-Bibliotheken, die man damit ansprechen kann.

Zend-Erweiterungn:

Diese sind eine spezielle Art von Erweiterung, die sich tief in die Zend-Engine einklinken und zusätzliche Funktionalität bereitstellen, zum Beispiel die XDebug-Erweiterung, die das Debuggen von PHP-Scripten erleichtert.

In der Regel werden die Erweiterungen in der php.ini-Konfigurationsdatei aktiviert und PHP lädt sie beim Start. Es gibt jedoch auch die Möglichkeit, Erweiterungen im PHP-Script von Hand nachzuladen per dl(). Da dies bei SAPIs, die Threads verwenden, Probleme macht, wird diese Möglichkeit dort vollständig deaktiviert und auch sonst wird davon abgeraten.

Zend-Erweiterungen können – da sie sich tief in die Zend-Engine einklinken – nur in der php.ini geladen werden.