Heim  >  Artikel  >  Backend-Entwicklung  >  PHP-Ausführungsprinzip

PHP-Ausführungsprinzip

高洛峰
高洛峰Original
2017-02-09 10:19:132602Durchsuche

PHP-Ausführungsprinzip

php ist eine Sprache mit sehr einfacher Anwendung und extrem hoher Entwicklungseffizienz. Ihre schwach typisierten Variablen können Programmierern die Definition einer großen Anzahl von Variablen ersparen Aufwand der Typkonvertierung etc. Es ist eine dynamische Sprache, die für die Webentwicklung geeignet ist.

1. Prinzipien und Merkmale des PHP-Designs

  • Multiprozessmodell: Dadurch kann sichergestellt werden, dass Prozesse sich nicht gegenseitig beeinflussen und die Ressourcennutzung von Prozessen verbessert wird schneller und bequemer

  • Schwach typisierte Sprache: Im Gegensatz zu stark typisierten Sprachen wie C, C++ und Java wird der Typ der Variablen in PHP nicht zu Beginn festgelegt Zur Laufzeit bestimmt, kann es implizit oder explizit typkonvertiert werden, was es bei der Entwicklung sehr flexibel macht.

  • Zend-Engine + Komponente ( ext)-Modus reduziert die interne Kopplung

  • Die mittlere Schicht (Sapi) isoliert den Webserver und PHP

  • Die Syntax ist einfach und flexibel, mit wenige Spezifikationen. Das hat Vor- und Nachteile. . .

2. Das vierschichtige System von PHP

PHP执行原理

php hat insgesamt ein vierschichtiges System von oben nach unten:

  • Zend-Engine: Zend ist vollständig in C implementiert und ist der Kernbestandteil von PHP. Es übersetzt PHP-Code in ausführbaren Opcode, verarbeitet und implementiert entsprechende Verarbeitungsmethoden (Prinzip: Niao Ges Blog implementiert grundlegende Datenstrukturen, Speicherzuweisung und -verwaltung und stellt entsprechende API-Methoden für die externe Verwendung bereit, die den Kern von allem bilden.

  • Erweiterungen: Rund um die Zend-Engine stellen Erweiterungen verschiedene grundlegende Dienste über Komponenten bereit. Häufig verwendete integrierte Funktionsarrays, Standardbibliotheken usw. werden bereitgestellt Erweiterungen Benutzer können bei Bedarf auch eigene Erweiterungen implementieren, um Funktionserweiterungen und andere Zwecke zu erreichen. Typische Anwendungen von Erweiterungen sind beispielsweise die PHP-Mittelschicht und das Rich-Text-Parsing, die derzeit von Tieba verwendet werden.

  • Sapi: Der vollständige Name von Sapi ist Server Application Programming Interface. Dabei handelt es sich um die Server-Anwendungsprogrammierschnittstelle, die es PHP ermöglicht, über eine Reihe von Hooks mit Peripheriedaten zu interagieren Dies ist ein sehr elegantes und erfolgreiches Design von PHP. PHP selbst ist erfolgreich von der übergeordneten Anwendung entkoppelt und kann nicht mehr berücksichtigt werden, und die Anwendung selbst kann auch implementiert werden unterschiedliche Verarbeitung entsprechend seinen eigenen Eigenschaften.

  • Anwendung der oberen Ebene: Dies ist die von Programmierern geschriebene Anwendung, die durch verschiedene Sapi-Methoden, z. B. die Implementierung von Webanwendungen über den Webserver, ausgeführt wird als Skript auf der Befehlszeile usw.

3. Sapi

Wie bereits erwähnt, ermöglicht Sapi externen Anwendungen die Kommunikation mit PHP über eine Reihe von Schnittstellen ausgetauscht werden und spezifische Verarbeitungsmethoden entsprechend unterschiedlicher Anwendungsmerkmale implementiert werden können:

  • Apache2handler: Bei Verwendung von Apache als Webserver ist die Verarbeitungsmethode bei der Ausführung im MOD_PHP-Modus jetzt ebenfalls vorhanden Das am häufigsten verwendete

  • cgi: Dies ist eine weitere Art der Interaktion zwischen Webserver und PHP, nämlich das Fastcgi-Protokoll

  • cli: Befehl Debugging-Anwendungsmodus

4. PHP-Code-Ausführungsprozess

PHP执行原理

Wie aus der Abbildung ersichtlich ist, wird PHP über Zend implementiert Engine Ein typischer dynamischer Sprachausführungsprozess wird beschrieben: Ein Code wird erhalten, und nach lexikalischer Analyse, Syntaxanalyse und anderen Phasen wird das Quellprogramm in Anweisungen (Opcodes) übersetzt, und dann führt die virtuelle Zend-Maschine diese Anweisungen nacheinander aus. PHP selbst ist in der C-Sprache implementiert, daher sind die letztendlich aufgerufenen Funktionen auch C-Sprachfunktionen.

Der Kern der PHP-Ausführung sind die nacheinander übersetzten Anweisungen, das heißt Opcode

Opcode ist die grundlegendste Einheit der PHP-Programmausführung. Ein Opcode besteht aus zwei Parametern (op1, op2), einem Rückgabewert und einer Verarbeitungsfunktion. Das PHP-Programm wird letztendlich in die sequentielle Ausführung einer Reihe von Opcode-Verarbeitungsfunktionen übersetzt.

Mehrere häufig verwendete Funktionen:

  • END_ASSIGN_SPEC_CV_CV_HANDLER: Variablenzuordnung (a=b)

  • ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER: Funktionsaufruf

  • ZEND_CONCAT_SPEC_CV_CV_HANDLER: String-Verkettung a.b

  • ZEND_ADD_SPEC_CV_CONST_HANDLER: Addition a+2

  • ZEND_IS_EQUAL_SPEC_CV_CON ST: Urteil von Gleichheit a==1

  • ZEND_IS_IDENTICAL_SPEC_CV_CONST: Beurteilung der Gleichheit a===1

5. Einführung in die Zend-Engine

Als Kern von PHP sind die wichtigsten Entwurfsmechanismen der Zend-Engine:

5.1 Implementierung der HashTable-Datenstruktur

HashTable ist die Kerndatenstruktur von Zend, die zur Implementierung fast aller verwendet wird Funktionen in PHP. Data array() ist eine typische Anwendung. Darüber hinaus werden innerhalb von Zend Funktionen wie Funktionssymboltabellen und Panoramavariablen über HashTable implementiert.

Die Zend-Hash-Tabelle implementiert eine typische Hash-Tabellen-Hash-Struktur und bietet gleichzeitig die Funktionen zum Vorwärts-, Rückwärts- und Array-Durchlauf durch Anhängen einer bidirektionalen verknüpften Liste. Die Struktur ist wie folgt:

PHP执行原理

Wie Sie sehen können, verfügt die Hash-Tabelle sowohl über eine Hash-Struktur in Form von Schlüssel->Werten als auch über einen doppelt verknüpften Listenmodus, wodurch sie sehr praktisch ist, um schnelle Suche und lineares Durchlaufen zu unterstützen.
Hash-Struktur : Die Hash-Struktur von Zend ist ein typisches Hash-Tabellenmodell, das Konflikte durch eine verknüpfte Liste löst. Es ist zu beachten, dass die Hash-Tabelle von Zend eine selbstwachsende Datenstruktur ist. Wenn die Anzahl der Hash-Tabellen voll ist, wird sie dynamisch um das Zweifache erweitert und Elemente neu positioniert. Die Anfangsgröße beträgt 8. Darüber hinaus hat Zend selbst bei der Durchführung der schnellen Schlüssel->Wertsuche einige Optimierungen vorgenommen, um den Prozess durch den Austausch von Raum gegen Zeit zu beschleunigen. Beispielsweise wird in jedem Element eine Variable nKeyLength verwendet, um die Länge des Schlüssels zur schnellen Bestimmung zu identifizieren.
Doppelt verknüpfte Liste: Die Zend-Hash-Tabelle implementiert die lineare Durchquerung von Elementen durch eine verknüpfte Listenstruktur. Theoretisch reicht es aus, eine einseitig verknüpfte Liste zum Durchlaufen zu verwenden. Der Hauptzweck der Verwendung einer zweiseitig verknüpften Liste besteht darin, das Durchlaufen schnell zu löschen und zu vermeiden. Die Zend-Hash-Tabelle ist eine zusammengesetzte Struktur, die gängige assoziative Arrays unterstützt und auch als sequentielle Indexnummern verwendet werden kann und sogar eine Mischung aus beiden ermöglicht.
PHP-Assoziatives Array: Assoziatives Array ist eine typische hash_table-Anwendung. Ein Abfrageprozess durchläuft die folgenden Schritte (wie aus dem Code ersichtlich ist, handelt es sich hierbei um einen üblichen Hash-Abfrageprozess und es werden einige schnelle Urteile hinzugefügt, um die Suche zu beschleunigen):

01  getKeyHashValue h;
02  index = n & nTableMask;
03  Bucket *p = arBucket[index];
04  while (p) {
05      if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
06          RETURN p->data;   
07      }
08      p=p->next;
09  }
10  RETURN FALTURE;

PHP Index-Array: Das Index-Array ist unser gemeinsames Array, auf das über Indizes zugegriffen wird. Beispielsweise wurde arr[0], Zend HashTable intern normalisiert , und dem Indextypschlüssel wird auch ein Hash-Wert und nKeyLength (0) zugewiesen. Die interne Mitgliedsvariable nNextFreeElement ist die aktuell zugewiesene maximale ID, die nach jedem Push automatisch um eins erhöht wird. Es ist dieser Normalisierungsprozess, der es PHP ermöglicht, eine Mischung aus assoziativen und nicht-assoziativen Daten zu erreichen. Aufgrund der Besonderheit des Push-Vorgangs wird die Reihenfolge der Indexschlüssel im PHP-Array nicht durch die Größe des Index bestimmt, sondern durch die Reihenfolge des Pushs. Zum Beispiel arr[1] = 2; arr[2] = 3; für einen Doppeltypschlüssel behandelt Zend HashTable ihn als Indexschlüssel

5.2 Implementierungsprinzip von PHP-Variablen

PHP ist eine schwach typisierte Sprache und unterscheidet die Variablentypen nicht streng. PHP-Variablen können in einfache Typen (int, sting, bool), Sammlungstypen (Array, Ressource, Objekt) und Konstanten (const) unterteilt werden. Alle Variablen haben unten die gleiche Struktur zval

zval ist eine sehr wichtige Datenstruktur in Zend, die zum Markieren und Implementieren von PHP-Variablen verwendet wird. Ihre Datenstruktur ist wie folgt:

struct _zval_struct {
    zvalue_value value;     /* value */
    zend_uint refcount__gc;  /* variable ref count */
    zend_uchar type;          /* active type */
    zend_uchar is_ref__gc;    /* if it is a ref variable */
};
typedef struct _zval_struct zval;

Unter ihnen

  • zval_value value ist der tatsächliche Wert der Variablen, insbesondere eine zvalue_value-Vereinigung:

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {                    /* string */
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value,used for array */
    zend_object_value obj;      /* object */
} zvalue_value;
  • zend_uint refcount__gc ist ein Zähler, der speichert, wie viele Variablen (oder Symbole, Symbole) auf den zval verweisen. Wenn die Variable generiert wird, ist ihr Refcount = 1. Typische Zuweisungsoperationen wie $a = $b erhöhen den Refcount von zval um 1, und die nicht gesetzte Operation verringert ihn entsprechend um 1. Vor PHP5.3 wurde der Referenzzählmechanismus zur Implementierung von GC verwendet. Wenn der Refcount eines zval kleiner als 0 war, ging die Zend-Engine davon aus, dass es keine Variable gab, die auf den zval zeigte, und gab daher den belegten Speicherplatz frei durch den zval. Aber manchmal sind die Dinge nicht so einfach. Wir werden später sehen, dass der einfache Referenzzählmechanismus den zirkulär referenzierten ZVAL nicht GC verwenden kann, selbst wenn die Variable, die auf den ZVAL zeigt, nicht gesetzt wurde, was zu einem Speicherverlust (Memory Leak) führt.

  • zend_uchar typeDieses Feld wird verwendet, um den tatsächlichen Typ der Variablen anzugeben. Zu den Variablen in PHP gehören vier Skalartypen (bool, int, float, string), zwei zusammengesetzte Typen (Array, Objekt) und zwei spezielle Typen (Ressource und NULL). Innerhalb von Zend entsprechen diese Typen den folgenden Makros (Codespeicherort phpsrc/Zend/zend.h)

#define IS_NULL     0
#define IS_LONG     1
#define IS_DOUBLE   2
#define IS_BOOL     3
#define IS_ARRAY    4
#define IS_OBJECT   5
#define IS_STRING   6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_ARRAY   9
#define IS_CALLABLE 10
  • is_ref__gc Dies Das Feld wird verwendet, um zu markieren, ob die Variable eine Referenzvariable ist. Für gewöhnliche Variablen ist der Wert 0 und für Referenzvariablen ist der Wert 1. Diese Variable wirkt sich auf die gemeinsame Nutzung, Trennung usw. von zval

    aus
5.2.1 Ganzzahl- und Gleitkommavariablen

Ganzzahl- und Gleitkommazahlen gehören zu den Grundtypen in PHP und sind ebenfalls einfache Variablen. Für Ganzzahlen und Gleitkommazahlen werden die entsprechenden Werte direkt in zvalue gespeichert. Ihre Typen sind lang bzw. doppelt.
Wie aus der Zvalue-Struktur ersichtlich ist, unterscheidet PHP im Gegensatz zu stark typisierten Sprachen wie C nicht zwischen int, unsigned int, long, long long und anderen Typen. Nur Ganzzahlen. Ein Typ ist lang. Daraus ist ersichtlich, dass in PHP der Wertebereich von Ganzzahlen durch die Anzahl der Compiler-Bits bestimmt wird und nicht festgelegt ist. Was passiert, wenn eine Ganzzahl in PHP den zulässigen Bereich überschreitet? PHP wandelt Ganzzahlen automatisch in Gleitkommazahlen um.

Bei Gleitkommazahlen wird, ähnlich wie bei Ganzzahlen, nicht zwischen Float und Double unterschieden, sondern nur ein einziger Typ vereinheitlicht: double

5.2.2 Zeichenvariablen
Zeichenvariablen sind wie Ganzzahlen auch Grundtypen und einfache Variablen in PHP. Aus der zvalue-Struktur ist ersichtlich, dass in PHP ein String aus einem Zeiger auf die tatsächlichen Daten und einer Längenstruktur besteht, die dem String in C++ ähnelt. Da die Länge im Gegensatz zu c durch eine tatsächliche Variable dargestellt wird, kann es sich bei der Zeichenfolge um Binärdaten (einschließlich 0) handeln. Gleichzeitig ist das Ermitteln der Zeichenfolgenlänge strlen eine O(1)-Operation

Gemeinsame String-Spleißmethoden und Geschwindigkeitsvergleich:

Angenommen, es gibt die folgenden 4 Variablen: strA='123'; strB = '456';

Machen Sie nun einen Vergleich und eine Erklärung der folgenden String-Splicing-Methoden:
1 res = strA.strB und res = „strAstrB“
In diesem Fall wird Zend einen Teil des Speichers neu mallocieren und ihn entsprechend verarbeiten. , seine Geschwindigkeit ist durchschnittlich.
2 strA = strA.strB
Dies ist die schnellste Methode. Zend führt eine direkte Neuzuordnung basierend auf der aktuellen strA durch, um wiederholte Kopien zu vermeiden.
3 res = intA.intB
Dies ist langsamer, da eine implizite Formatkonvertierung erfolgt ist erforderlich, Sie sollten auch beim Schreiben von Programmen darauf achten, dies zu vermeiden
4 strA = sprintf („%s%s“, strA, strB);
Dies ist die langsamste Methode, da sprintf keine ist Die Sprachstruktur in PHP erfordert viel Zeit, um das Format zu identifizieren und zu verarbeiten. Darüber hinaus ist der Mechanismus selbst malloc. Die Sprintf-Methode ist jedoch die am besten lesbare Methode und kann in der Praxis je nach den spezifischen Umständen flexibel ausgewählt werden.

5.2.3 Array-Variablen
PHPs Array wird natürlich durch Zend Hash Table implementiert.

Wie implementiert man die foreach-Operation? Foreach eines Arrays wird durch Durchlaufen der doppelt verknüpften Liste in der Hashtabelle vervollständigt. Bei Index-Arrays ist die Durchquerung von foreach viel effizienter als bei for, sodass keine Suche nach Schlüssel->Werten erforderlich ist. Die Zähloperation ruft direkt die Operation HashTable->NumOfElements, O(1) auf. Für eine Zeichenfolge wie „123“ konvertiert Zend sie in ihre Ganzzahlform. arr[‘123’] und arr[123]

5.3 PHP-Variablenverwaltung – Referenzzählung und Copy-on-Write
Referenzzählung wird häufig beim Speicherrecycling, bei String-Operationen usw. verwendet. Die Referenzzählung von Zval wird über die Mitgliedsvariablen is_ref und ref_count implementiert. Durch die Referenzzählung können mehrere Variablen dieselben Daten teilen. Vermeiden Sie den hohen Verbrauch, der durch häufiges Kopieren entsteht. Beim Ausführen einer Zuweisungsoperation für

verweist Zend auf die Variable zval und ref_count++. Beim Ausführen einer nicht gesetzten Operation wird der entsprechende ref_count-1 verwendet. Der Zerstörungsvorgang wird nur ausgeführt, wenn ref_count auf 0 reduziert wird. Wenn es sich um eine Referenzzuweisung handelt, ändert Zend is_ref auf 1.

PHP-Variablen realisieren die gemeinsame Nutzung von Daten durch Referenzzählung. Was passiert, wenn einer der Variablenwerte geändert wird? Wenn Zend beim Versuch, eine Variable zu schreiben, feststellt, dass der ZVAL, auf den die Variable zeigt, von mehreren Variablen gemeinsam genutzt wird, kopiert es einen ZVAL mit einem Ref_Count von 1 und verringert den RefCount des ursprünglichen ZVAL. Dieser Vorgang wird als „ZVAL-Trennung“ bezeichnet ". Es ist ersichtlich, dass Zend nur Kopiervorgänge ausführt, wenn ein Schreibvorgang auftritt, daher wird es auch als

Copy-on-Write (Copy-on-Write)

Für Referenzvariablen bezeichnet Anforderungen und Nicht-Referenz Im Gegensatz dazu müssen

durch Referenz zugewiesene Variablen gebündelt werden. Das Ändern einer Variablen ändert alle gebündelten Variablen.

5.4 Implementierung von lokalen Variablen und globalen Variablen in PHP:
Wie werden lokale Variablen und globale Variablen in PHP implementiert? Bei einer Anfrage kann PHP jederzeit

zwei Symboltabellen (symbol_table und active_symbol_table) sehen, von denen die erstere zur Verwaltung globaler Variablen verwendet wird. Letzteres ist ein Zeiger, der auf die aktuell aktive Variablensymboltabelle zeigt. Wenn das Programm eine Funktion aufruft, weist Zend ihr eine Symboltabelle x zu und zeigt active_symbol_table auf a. Auf diese Weise wird die Unterscheidung zwischen globalen und lokalen Variablen erreicht.

Variablenwerte abrufen: Die Symboltabelle von PHP wird über hash_table implementiert. Beim Abrufen wird der entsprechende zval entsprechend der Kennung ermittelt und zurückgegeben.

Globale Variablen in Funktionen verwenden: In Funktionen können wir globale Variablen verwenden, indem wir sie explizit als global deklarieren.

Erstellen Sie einen Verweis auf die Variable mit demselben Namen in symbol_table in active_symbol_table (Wenn der Wert der Referenzvariablen aktualisiert werden muss, aktualisieren alle ihn gemeinsam, wenn keine Variable mit demselben Namen vorhanden ist). symbol_table, es wird zuerst erstellt.

Referenz:

  • http://www.php.cn/

  • http://www.php.cn/

  • [http://www.php.cn/


PHP-Ausführungsprinzip

php ist eine Sprache mit sehr einfacher Anwendung und extrem hoher Entwicklungseffizienz. Ihre schwach typisierten Variablen können Programmierern die Definition einer großen Anzahl von Variablen ersparen Aufwand der Typkonvertierung etc. Es ist eine dynamische Sprache, die für die Webentwicklung geeignet ist.

1. Prinzipien und Merkmale des PHP-Designs

  • Multiprozessmodell: Dadurch kann sichergestellt werden, dass Prozesse sich nicht gegenseitig beeinflussen und die Ressourcennutzung von Prozessen verbessert wird schneller und bequemer

  • Schwach typisierte Sprache: Im Gegensatz zu stark typisierten Sprachen wie C, C++ und Java wird der Typ der Variablen in PHP nicht zu Beginn festgelegt Zur Laufzeit bestimmt, kann es implizit oder explizit typkonvertiert werden, was es bei der Entwicklung sehr flexibel macht.

  • Zend-Engine + Komponente ( ext)-Modus reduziert die interne Kopplung

  • Die mittlere Schicht (Sapi) isoliert den Webserver und PHP

  • Die Syntax ist einfach und flexibel, mit wenige Spezifikationen. Das hat Vor- und Nachteile. . .

2. Das vierschichtige System von PHP

PHP执行原理

php hat insgesamt ein vierschichtiges System von oben nach unten:

  • Zend-Engine: Zend ist vollständig in C implementiert und ist der Kernbestandteil von PHP. Es übersetzt PHP-Code in ausführbaren Opcode, verarbeitet und implementiert entsprechende Verarbeitungsmethoden (Prinzip: Niao Ges Blog implementiert grundlegende Datenstrukturen, Speicherzuweisung und -verwaltung und stellt entsprechende API-Methoden für die externe Verwendung bereit, die den Kern von allem bilden.

  • Erweiterungen: Rund um die Zend-Engine stellen Erweiterungen verschiedene grundlegende Dienste über Komponenten bereit. Häufig verwendete integrierte Funktionsarrays, Standardbibliotheken usw. werden bereitgestellt Erweiterungen Benutzer können bei Bedarf auch eigene Erweiterungen implementieren, um Funktionserweiterungen und andere Zwecke zu erreichen. Typische Anwendungen von Erweiterungen sind beispielsweise die PHP-Mittelschicht und das Rich-Text-Parsing, die derzeit von Tieba verwendet werden.

  • Sapi: Der vollständige Name von Sapi ist Server Application Programming Interface. Dabei handelt es sich um die Server-Anwendungsprogrammierschnittstelle, die es PHP ermöglicht, über eine Reihe von Hooks mit Peripheriedaten zu interagieren Dies ist ein sehr elegantes und erfolgreiches Design von PHP. PHP selbst ist erfolgreich von der übergeordneten Anwendung entkoppelt und kann nicht mehr berücksichtigt werden, und die Anwendung selbst kann auch implementiert werden unterschiedliche Verarbeitung entsprechend seinen eigenen Eigenschaften.

  • Anwendung der oberen Ebene: Dies ist die von Programmierern geschriebene Anwendung, die durch verschiedene Sapi-Methoden, z. B. die Implementierung von Webanwendungen über den Webserver, ausgeführt wird als Skript auf der Befehlszeile usw.

3. Sapi

Wie bereits erwähnt, ermöglicht Sapi externen Anwendungen die Kommunikation mit PHP über eine Reihe von Schnittstellen ausgetauscht werden und spezifische Verarbeitungsmethoden entsprechend unterschiedlicher Anwendungsmerkmale implementiert werden können:

  • Apache2handler: Bei Verwendung von Apache als Webserver ist die Verarbeitungsmethode bei der Ausführung im MOD_PHP-Modus jetzt ebenfalls vorhanden Das am häufigsten verwendete

  • cgi: Dies ist eine weitere Art der Interaktion zwischen Webserver und PHP, nämlich das Fastcgi-Protokoll

  • cli: Befehl Debugging-Anwendungsmodus

4. PHP-Code-Ausführungsprozess

PHP执行原理

Wie aus der Abbildung ersichtlich ist, wird PHP über Zend implementiert Engine Ein typischer dynamischer Sprachausführungsprozess wird beschrieben: Ein Code wird erhalten, und nach lexikalischer Analyse, Syntaxanalyse und anderen Phasen wird das Quellprogramm in Anweisungen (Opcodes) übersetzt, und dann führt die virtuelle Zend-Maschine diese Anweisungen nacheinander aus. PHP selbst ist in der C-Sprache implementiert, daher sind die letztendlich aufgerufenen Funktionen auch C-Sprachfunktionen.

Der Kern der PHP-Ausführung sind die nacheinander übersetzten Anweisungen, das heißt Opcode

Opcode ist die grundlegendste Einheit der PHP-Programmausführung. Ein Opcode besteht aus zwei Parametern (op1, op2), einem Rückgabewert und einer Verarbeitungsfunktion. Das PHP-Programm wird letztendlich in die sequentielle Ausführung einer Reihe von Opcode-Verarbeitungsfunktionen übersetzt.

Mehrere häufig verwendete Funktionen:

  • END_ASSIGN_SPEC_CV_CV_HANDLER: Variablenzuordnung (a=b)

  • ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER: Funktionsaufruf

  • ZEND_CONCAT_SPEC_CV_CV_HANDLER: String-Verkettung a.b

  • ZEND_ADD_SPEC_CV_CONST_HANDLER: Addition a+2

  • ZEND_IS_EQUAL_SPEC_CV_CON ST: Urteil von Gleichheit a==1

  • ZEND_IS_IDENTICAL_SPEC_CV_CONST: Beurteilung der Gleichheit a===1

5. Einführung in die Zend-Engine

Als Kern von PHP sind die wichtigsten Entwurfsmechanismen der Zend-Engine:

5.1 Implementierung der HashTable-Datenstruktur

HashTable ist die Kerndatenstruktur von Zend, die zur Implementierung fast aller verwendet wird Funktionen in PHP. Data array() ist eine typische Anwendung. Darüber hinaus werden innerhalb von Zend Funktionen wie Funktionssymboltabellen und Panoramavariablen über HashTable implementiert.

Die Zend-Hash-Tabelle implementiert eine typische Hash-Tabellen-Hash-Struktur und bietet gleichzeitig die Funktionen zum Vorwärts-, Rückwärts- und Array-Durchlauf durch Anhängen einer bidirektionalen verknüpften Liste. Die Struktur ist wie folgt:

PHP执行原理

Wie Sie sehen können, verfügt die Hash-Tabelle sowohl über eine Hash-Struktur in Form von Schlüssel->Werten als auch über einen doppelt verknüpften Listenmodus, wodurch sie sehr praktisch ist, um schnelle Suche und lineares Durchlaufen zu unterstützen.
Hash-Struktur : Die Hash-Struktur von Zend ist ein typisches Hash-Tabellenmodell, das Konflikte durch eine verknüpfte Liste löst. Es ist zu beachten, dass die Hash-Tabelle von Zend eine selbstwachsende Datenstruktur ist. Wenn die Anzahl der Hash-Tabellen voll ist, wird sie dynamisch um das Zweifache erweitert und Elemente neu positioniert. Die Anfangsgröße beträgt 8. Darüber hinaus hat Zend selbst bei der Durchführung der schnellen Schlüssel->Wertsuche einige Optimierungen vorgenommen, um den Prozess durch den Austausch von Raum gegen Zeit zu beschleunigen. Beispielsweise wird in jedem Element eine Variable nKeyLength verwendet, um die Länge des Schlüssels zur schnellen Bestimmung zu identifizieren.
Doppelt verknüpfte Liste: Die Zend-Hash-Tabelle implementiert die lineare Durchquerung von Elementen durch eine verknüpfte Listenstruktur. Theoretisch reicht es aus, eine einseitig verknüpfte Liste zum Durchlaufen zu verwenden. Der Hauptzweck der Verwendung einer zweiseitig verknüpften Liste besteht darin, das Durchlaufen schnell zu löschen und zu vermeiden. Die Zend-Hash-Tabelle ist eine zusammengesetzte Struktur, die gängige assoziative Arrays unterstützt und auch als sequentielle Indexnummern verwendet werden kann und sogar eine Mischung aus beiden ermöglicht.
PHP-Assoziatives Array: Assoziatives Array ist eine typische hash_table-Anwendung. Ein Abfrageprozess durchläuft die folgenden Schritte (wie aus dem Code ersichtlich ist, handelt es sich hierbei um einen üblichen Hash-Abfrageprozess und es werden einige schnelle Urteile hinzugefügt, um die Suche zu beschleunigen):

01  getKeyHashValue h;
02  index = n & nTableMask;
03  Bucket *p = arBucket[index];
04  while (p) {
05      if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
06          RETURN p->data;   
07      }
08      p=p->next;
09  }
10  RETURN FALTURE;

PHP Index-Array: Das Index-Array ist unser gemeinsames Array, auf das über Indizes zugegriffen wird. Beispielsweise wurde arr[0], Zend HashTable intern normalisiert , und dem Indextypschlüssel wird auch ein Hash-Wert und nKeyLength (0) zugewiesen. Die interne Mitgliedsvariable nNextFreeElement ist die aktuell zugewiesene maximale ID, die nach jedem Push automatisch um eins erhöht wird. Es ist dieser Normalisierungsprozess, der es PHP ermöglicht, eine Mischung aus assoziativen und nicht-assoziativen Daten zu erreichen. Aufgrund der Besonderheit des Push-Vorgangs wird die Reihenfolge der Indexschlüssel im PHP-Array nicht durch die Größe des Index bestimmt, sondern durch die Reihenfolge des Pushs. Zum Beispiel arr[1] = 2; arr[2] = 3; für einen Doppeltypschlüssel behandelt Zend HashTable ihn als Indexschlüssel

5.2 Implementierungsprinzip von PHP-Variablen

PHP ist eine schwach typisierte Sprache und unterscheidet die Variablentypen nicht streng. PHP-Variablen können in einfache Typen (int, sting, bool), Sammlungstypen (Array, Ressource, Objekt) und Konstanten (const) unterteilt werden. Alle Variablen haben unten die gleiche Struktur zval

zval ist eine sehr wichtige Datenstruktur in Zend, die zum Markieren und Implementieren von PHP-Variablen verwendet wird. Ihre Datenstruktur ist wie folgt:

struct _zval_struct {
    zvalue_value value;     /* value */
    zend_uint refcount__gc;  /* variable ref count */
    zend_uchar type;          /* active type */
    zend_uchar is_ref__gc;    /* if it is a ref variable */
};
typedef struct _zval_struct zval;

Unter ihnen

  • zval_value value ist der tatsächliche Wert der Variablen, insbesondere eine zvalue_value-Vereinigung:

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {                    /* string */
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value,used for array */
    zend_object_value obj;      /* object */
} zvalue_value;
  • zend_uint refcount__gc ist ein Zähler, der speichert, wie viele Variablen (oder Symbole, Symbole) auf den zval verweisen. Wenn die Variable generiert wird, ist ihr Refcount = 1. Typische Zuweisungsoperationen wie $a = $b erhöhen den Refcount von zval um 1, und die nicht gesetzte Operation verringert ihn entsprechend um 1. Vor PHP5.3 wurde der Referenzzählmechanismus zur Implementierung von GC verwendet. Wenn der Refcount eines zval kleiner als 0 war, ging die Zend-Engine davon aus, dass es keine Variable gab, die auf den zval zeigte, und gab daher den belegten Speicherplatz frei durch den zval. Aber manchmal sind die Dinge nicht so einfach. Wir werden später sehen, dass der einfache Referenzzählmechanismus den zirkulär referenzierten ZVAL nicht GC verwenden kann, selbst wenn die Variable, die auf den ZVAL zeigt, nicht gesetzt wurde, was zu einem Speicherverlust (Memory Leak) führt.

  • zend_uchar typeDieses Feld wird verwendet, um den tatsächlichen Typ der Variablen anzugeben. Zu den Variablen in PHP gehören vier Skalartypen (bool, int, float, string), zwei zusammengesetzte Typen (Array, Objekt) und zwei spezielle Typen (Ressource und NULL). Innerhalb von Zend entsprechen diese Typen den folgenden Makros (Codespeicherort phpsrc/Zend/zend.h)

#define IS_NULL     0
#define IS_LONG     1
#define IS_DOUBLE   2
#define IS_BOOL     3
#define IS_ARRAY    4
#define IS_OBJECT   5
#define IS_STRING   6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_ARRAY   9
#define IS_CALLABLE 10
  • is_ref__gc Dies Das Feld wird verwendet, um zu markieren, ob die Variable eine Referenzvariable ist. Für gewöhnliche Variablen ist der Wert 0 und für Referenzvariablen ist der Wert 1. Diese Variable wirkt sich auf die gemeinsame Nutzung, Trennung usw. von zval

    aus
5.2.1 Ganzzahl- und Gleitkommavariablen

Ganzzahl- und Gleitkommazahlen gehören zu den Grundtypen in PHP und sind ebenfalls einfache Variablen. Für Ganzzahlen und Gleitkommazahlen werden die entsprechenden Werte direkt in zvalue gespeichert. Ihre Typen sind lang bzw. doppelt.
Wie aus der Zvalue-Struktur ersichtlich ist, unterscheidet PHP im Gegensatz zu stark typisierten Sprachen wie C nicht zwischen int, unsigned int, long, long long und anderen Typen. Nur Ganzzahlen. Ein Typ ist lang. Daraus ist ersichtlich, dass in PHP der Wertebereich von Ganzzahlen durch die Anzahl der Compiler-Bits bestimmt wird und nicht festgelegt ist. Was passiert, wenn eine Ganzzahl in PHP den zulässigen Bereich überschreitet? PHP wandelt Ganzzahlen automatisch in Gleitkommazahlen um.

Bei Gleitkommazahlen wird, ähnlich wie bei Ganzzahlen, nicht zwischen Float und Double unterschieden, sondern nur ein einziger Typ vereinheitlicht: double

5.2.2 Zeichenvariablen
Zeichenvariablen sind wie Ganzzahlen auch Grundtypen und einfache Variablen in PHP. Aus der zvalue-Struktur ist ersichtlich, dass in PHP ein String aus einem Zeiger auf die tatsächlichen Daten und einer Längenstruktur besteht, die dem String in C++ ähnelt. Da die Länge im Gegensatz zu c durch eine tatsächliche Variable dargestellt wird, kann es sich bei der Zeichenfolge um Binärdaten (einschließlich 0) handeln. Gleichzeitig ist das Ermitteln der Zeichenfolgenlänge strlen eine O(1)-Operation

Gemeinsame String-Spleißmethoden und Geschwindigkeitsvergleich:

Angenommen, es gibt die folgenden 4 Variablen: strA='123'; strB = '456';

Machen Sie nun einen Vergleich und eine Erklärung der folgenden String-Splicing-Methoden:
1 res = strA.strB und res = „strAstrB“
In diesem Fall wird Zend einen Teil des Speichers neu mallocieren und ihn entsprechend verarbeiten. , seine Geschwindigkeit ist durchschnittlich.
2 strA = strA.strB
Dies ist die schnellste Methode. Zend führt eine direkte Neuzuordnung basierend auf der aktuellen strA durch, um wiederholte Kopien zu vermeiden.
3 res = intA.intB
Dies ist langsamer, da eine implizite Formatkonvertierung erfolgt ist erforderlich, Sie sollten auch beim Schreiben von Programmen darauf achten, dies zu vermeiden
4 strA = sprintf („%s%s“, strA, strB);
Dies ist die langsamste Methode, da sprintf keine ist Die Sprachstruktur in PHP erfordert viel Zeit, um das Format zu identifizieren und zu verarbeiten. Darüber hinaus ist der Mechanismus selbst malloc. Die Sprintf-Methode ist jedoch die am besten lesbare Methode und kann in der Praxis je nach den spezifischen Umständen flexibel ausgewählt werden.

5.2.3 Array-Variablen
PHPs Array wird natürlich durch Zend Hash Table implementiert.

Wie implementiert man die foreach-Operation? Foreach eines Arrays wird durch Durchlaufen der doppelt verknüpften Liste in der Hashtabelle vervollständigt. Bei Index-Arrays ist die Durchquerung von foreach viel effizienter als bei for, sodass keine Suche nach Schlüssel->Werten erforderlich ist. Die Zähloperation ruft direkt die Operation HashTable->NumOfElements, O(1) auf. Für eine Zeichenfolge wie „123“ konvertiert Zend sie in ihre Ganzzahlform. arr[‘123’] und arr[123]

5.3 PHP-Variablenverwaltung – Referenzzählung und Copy-on-Write
Referenzzählung wird häufig beim Speicherrecycling, bei String-Operationen usw. verwendet. Die Referenzzählung von Zval wird über die Mitgliedsvariablen is_ref und ref_count implementiert. Durch die Referenzzählung können mehrere Variablen dieselben Daten teilen. Vermeiden Sie den hohen Verbrauch, der durch häufiges Kopieren entsteht. Beim Ausführen einer Zuweisungsoperation für

verweist Zend auf die Variable zval und ref_count++. Beim Ausführen einer nicht gesetzten Operation wird der entsprechende ref_count-1 verwendet. Der Zerstörungsvorgang wird nur ausgeführt, wenn ref_count auf 0 reduziert wird. Wenn es sich um eine Referenzzuweisung handelt, ändert Zend is_ref auf 1.

PHP-Variablen realisieren die gemeinsame Nutzung von Daten durch Referenzzählung. Was passiert, wenn einer der Variablenwerte geändert wird? Wenn Zend beim Versuch, eine Variable zu schreiben, feststellt, dass der ZVAL, auf den die Variable zeigt, von mehreren Variablen gemeinsam genutzt wird, kopiert es einen ZVAL mit einem Ref_Count von 1 und verringert den RefCount des ursprünglichen ZVAL. Dieser Vorgang wird als „ZVAL-Trennung“ bezeichnet ". Es ist ersichtlich, dass Zend nur Kopiervorgänge ausführt, wenn ein Schreibvorgang auftritt, daher wird es auch als

Copy-on-Write (Copy-on-Write)

Für Referenzvariablen bezeichnet Anforderungen und Nicht-Referenz Im Gegensatz dazu müssen

durch Referenz zugewiesene Variablen gebündelt werden. Das Ändern einer Variablen ändert alle gebündelten Variablen.

5.4 Implementierung lokaler Variablen und globaler Variablen in PHP:
Wie werden lokale Variablen und globale Variablen in PHP implementiert? Bei einer Anfrage kann PHP jederzeit

zwei Symboltabellen (symbol_table und active_symbol_table) sehen, von denen die erstere zur Pflege globaler Variablen verwendet wird. Letzteres ist ein Zeiger, der auf die aktuell aktive Variablensymboltabelle zeigt. Wenn das Programm eine Funktion aufruft, weist zend ihr eine Symboltabelle x zu und zeigt active_symbol_table auf a. Auf diese Weise wird die Unterscheidung zwischen globalen und lokalen Variablen erreicht.

Variablenwerte abrufen: Die PHP-Symboltabelle wird über hash_table implementiert. Beim Abrufen wird der entsprechende zval aus der Tabelle gefunden und entsprechend der Kennung zurückgegeben.

Globale Variablen in Funktionen verwenden: In Funktionen können wir globale Variablen verwenden, indem wir sie explizit als global deklarieren.

Erstellen Sie einen Verweis auf die Variable mit demselben Namen in symbol_table in active_symbol_table (Wenn der Wert der Referenzvariablen aktualisiert werden muss, aktualisieren alle ihn gemeinsam, wenn keine Variable mit demselben Namen vorhanden ist). symbol_table, es wird zuerst erstellt.

Weitere PHP-Ausführungsprinzipien und verwandte Artikel finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn