Maison >développement back-end >tutoriel php >Principe d'exécution PHP

Principe d'exécution PHP

高洛峰
高洛峰original
2017-02-09 10:19:132654parcourir

Principe d'exécution de PHP

php est un langage avec une application très simple et une efficacité de développement extrêmement élevée. Ses variables faiblement typées peuvent éviter aux programmeurs de définir un grand nombre de variables. effort de conversion de type, etc. C'est un langage dynamique adapté au développement Web.

1. Principes et caractéristiques de la conception PHP

  • Modèle multi-processus : cela peut garantir que les processus ne sont pas affectés les uns par les autres et que l'utilisation des ressources des processus est plus rapide et plus pratique

  • Langage faiblement typé : contrairement aux langages fortement typés tels que C, C, Java et d'autres langages, le type de variables en PHP n'est pas déterminé au début, il est déterminé au moment de l'exécution, il peut être converti en type implicitement ou explicitement, ce qui le rend très flexible dans le développement. Les programmeurs n'ont pas besoin de prêter attention au problème de type variable

  • Composant du moteur Zend. Le mode (ext ) réduit le couplage interne

  • La couche intermédiaire (sapi) isole le serveur web et php

  • La syntaxe est simple et flexible, avec peu de spécifications. Cela présente des avantages et des inconvénients. . .

2. Le système à quatre couches de PHP

PHP执行原理

php a un total de système à quatre couches de haut en bas :

  • Zend Engine : Zend est entièrement implémenté en C et est la partie centrale de PHP. Il traduit le code PHP en opcode exécutable, traite et implémente les méthodes de traitement correspondantes (principe : Le blog de Brother Niao), implémente les structures de données de base, l'allocation et la gestion de la mémoire, et fournit les méthodes API correspondantes pour une utilisation externe, qui sont au cœur de tout.

  • Extensions : Autour du moteur Zend, les extensions fournissent divers services de base via des composants couramment utilisés, des tableaux de fonctions intégrés, des bibliothèques standard, etc. Les utilisateurs peuvent également implémenter leurs propres extensions si nécessaire pour réaliser une expansion fonctionnelle et à d'autres fins. Par exemple, la couche intermédiaire PHP et l'analyse de texte enrichi actuellement utilisées par Tieba sont des applications typiques des extensions).

  • Sapi : Le nom complet de Sapi est Server Application Programing Interface, qui est l'interface de programmation d'applications serveur qui permet à PHP d'interagir avec les données périphériques via une série de hooks. Fonctions. Il s'agit d'une conception très élégante et réussie de PHP. Grâce à sapi, PHP lui-même est découplé et isolé avec succès de l'application de couche supérieure. PHP ne peut plus considérer comment être compatible avec différentes applications, et l'application elle-même peut également implémenter. traitement différent selon ses propres caractéristiques.

  • Application de couche supérieure : Il s'agit du programme d'application écrit par les programmeurs. Différents modes d'application sont obtenus via différentes méthodes sapi, telles que la mise en œuvre d'applications Web via un serveur Web, exécuter en tant que script sur la ligne de commande, etc.

3 Sapi

Comme mentionné précédemment, Sapi permet aux applications externes de communiquer avec php via une série d'interfaces de données. peuvent être échangées et des méthodes de traitement spécifiques peuvent être implémentées en fonction de différentes caractéristiques de l'application :

  • apache2handler : en utilisant Apache comme serveur Web, la méthode de traitement lors de l'exécution en mode MOD_PHP est également. maintenant Le plus largement utilisé

  • cgi : Il s'agit d'un autre moyen d'interaction entre le serveur Web et php, qui est le protocole fastcgi

  • cli : Mode d'application de débogage des commandes

4. Processus d'exécution du code PHP

PHP执行原理

Comme le montre la figure, php est implémenté via le Moteur Zend Un processus d'exécution de langage dynamique typique est décrit : un morceau de code est obtenu, et après une analyse lexicale, une analyse syntaxique et d'autres étapes, le programme source est traduit en instructions (opcodes), puis la machine virtuelle Zend exécute ces instructions séquentiellement . PHP lui-même est implémenté en langage C, donc les fonctions finalement appelées sont également des fonctions en langage C.

Le cœur de l'exécution de PHP est constitué des instructions traduites une par une, c'est-à-dire opcode

L'opcode est l'unité la plus basique de l'exécution d'un programme PHP. Un opcode se compose de deux paramètres (op1, op2), d'une valeur de retour et d'une fonction de traitement. Le programme PHP se traduit finalement par l'exécution séquentielle d'un ensemble de fonctions de traitement d'opcodes.

Plusieurs fonctions couramment utilisées :

  • END_ASSIGN_SPEC_CV_CV_HANDLER : allocation de variable (a=b)

  • ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER : appel de fonction

  • ZEND_CONCAT_SPEC_CV_CV_HANDLER : Concaténation de chaînes a.b

  • ZEND_ADD_SPEC_CV_CONST_HANDLER : Ajout d'un 2

  • ZEND_ IS_EQUAL_SPEC_CV _CONST : égalité de jugement a ==1

  • ZEND_IS_IDENTICAL_SPEC_CV_CONST : Déterminer l'égalité a===1

5. Introduction au moteur Zend

Zend Le moteur est le cœur de php. Les principaux mécanismes de conception sont :

5.1 Implémentation de la structure de données HashTable

HashTable est la structure de données de base de Zend. Elle est utilisée pour implémenter presque toutes les fonctions de php. PHP data array() est une application typique. De plus, dans Zend, des fonctions telles que les tables de symboles de fonction et les variables panoramiques sont implémentées via HashTable.

La table de hachage Zend implémente une structure de hachage de table de hachage typique et fournit en même temps les fonctions de parcours avant, arrière et de tableau en attachant une liste chaînée bidirectionnelle. La structure est la suivante :

PHP执行原理

Comme vous pouvez le voir, la table de hachage a à la fois une structure de hachage sous forme de clé->valeur et un mode de liste doublement chaînée, ce qui la rend très pratique pour prendre en charge la recherche rapide et le parcours linéaire.


Structure de hachage  : La structure de hachage de Zend est un modèle de table de hachage typique, qui résout les conflits via une liste chaînée. Il convient de noter que la table de hachage de Zend est une structure de données à croissance automatique Lorsque le nombre de tables de hachage est plein, elle s'étendra dynamiquement de 2 fois et repositionnera les éléments. La taille initiale est de 8. De plus, lors de l'exécution d'une recherche rapide clé->valeur, zend lui-même a également apporté quelques optimisations pour accélérer le processus en échangeant de l'espace contre du temps. Par exemple, une variable nKeyLength est utilisée dans chaque élément pour identifier la longueur de la clé pour une détermination rapide.
Liste chaînée double : la table de hachage Zend implémente un parcours linéaire d'éléments via une structure de liste chaînée. Théoriquement, il suffit d'utiliser une liste chaînée unidirectionnelle pour le parcours. L'objectif principal de l'utilisation d'une liste doublement chaînée est de supprimer rapidement et d'éviter le parcours. La table de hachage Zend est une structure composite lorsqu'elle est utilisée comme tableau, elle prend en charge les tableaux associatifs communs et peut également être utilisée comme numéros d'index séquentiels, et permet même un mélange des deux.
Tableau associatif PHP : Le tableau associatif est une application hash_table typique. Un processus de requête passe par les étapes suivantes (comme le montre le code, il s'agit d'un processus de requête de hachage courant et quelques jugements rapides sont ajoutés pour accélérer la recherche) :

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 tableau d'index : Le tableau d'index est notre tableau commun, accessible via des indices. Par exemple, arr[0], Zend HashTable a été normalisé en interne, et la clé de type d'index se voit également attribuer une valeur de hachage et nKeyLength (0). La variable membre interne nNextFreeElement est l'identifiant maximum actuellement attribué, qui est automatiquement augmenté de un après chaque poussée. C'est ce processus de normalisation qui permet à PHP de réaliser un mélange de données associatives et non associatives. En raison de la particularité de l'opération push, l'ordre des clés d'index dans le tableau PHP n'est pas déterminé par la taille de l'indice, mais par l'ordre du push. Par exemple, arr[1] = 2; arr[2] = 3; pour une clé de type double, Zend HashTable la traitera comme une clé d'index

5.2 Principe d'implémentation des variables PHP

PHP est un langage faiblement typé et ne distingue pas strictement les types de variables. Les variables PHP peuvent être divisées en types simples (int, sting, bool), types de collection (tableau, ressource, objet) et constantes (const). Toutes les variables ont la même structure en bas

zval.

zval est une structure de données très importante dans zend, utilisée pour marquer et implémenter des variables PHP. Sa structure de données est la suivante :

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;
Parmi elles,

    <.>
  • zval_value value

    est la valeur réelle de la variable, en particulier une union zvalue_value :

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

    est un compteur utilisé pour enregistrer le nombre de variables (ou symboles, symboles) pointant vers le zval. Lorsque la variable est générée, son refcount=1. Les opérations d'affectation typiques telles que $a = $b augmenteront le refcount de zval de 1, et l'opération de non-définition le diminuera de 1 en conséquence. Avant PHP5.3, le mécanisme de comptage de références était utilisé pour implémenter GC Si le refcount d'un zval était inférieur à 0, le moteur Zend penserait qu'il n'y avait aucune variable pointant vers le zval, et libérerait donc l'espace mémoire occupé par. le zval. Mais parfois, les choses ne sont pas si simples. Nous verrons plus tard que le simple mécanisme de comptage de références ne peut pas GC le zval référencé circulairement, même si la variable pointant vers le zval a été non définie, ce qui entraîne une fuite de mémoire (Memory Leak).

  • type zend_uchar

    Ce champ est utilisé pour indiquer le type réel de la variable. Les variables en PHP incluent quatre types scalaires (bool, int, float, string), deux types composites (tableau, objet) et deux types spéciaux (ressource et NULL). Dans zend, ces types correspondent aux macros suivantes (emplacement du code 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

    Ceci Le champ est utilisé pour indiquer si la variable est une variable de référence. Pour les variables ordinaires, la valeur est 0 et pour les variables de référence, la valeur est 1. Cette variable affectera le partage, la séparation, etc. de zval

5.2.1 Variables entières et à virgule flottante

Les nombres entiers et à virgule flottante sont l'un des types de base en PHP et sont également des variables simples. Pour les entiers et les nombres à virgule flottante, les valeurs correspondantes sont stockées directement dans zvalue. Leurs types sont respectivement longs et doubles.
Comme le montre la structure zvalue, pour les types entiers, contrairement aux langages fortement typés tels que C, PHP ne fait pas de distinction entre les types int, int non signé, long, long long et autres. entiers uniquement Un type est long. De là, on peut voir qu'en PHP, la plage de valeurs des entiers est déterminée par le nombre de bits du compilateur et n'est pas fixe. Que se passe-t-il si un entier sort des limites en php ? PHP convertira automatiquement les entiers en types à virgule flottante

Pour les nombres à virgule flottante, similaires aux entiers, il ne fait pas de différence entre float et double mais n'unifie qu'un seul type : double

5.2.2 Variables de caractères

Comme les entiers, les variables de caractères sont également des types de base et des variables simples en PHP. La structure zvalue montre qu'en PHP, une chaîne est composée d'un pointeur vers les données réelles et d'une structure de longueur, similaire à la chaîne en C. Puisque la longueur est représentée par une variable réelle, contrairement à c, sa chaîne peut être une donnée binaire (y compris 0). En même temps, en PHP, trouver la longueur de la chaîne strlen est une opération O(1)

. Méthodes courantes d'épissage de chaînes et comparaison de vitesse :

Supposons qu'il existe les 4 variables suivantes : strA='123'; strB = '456'; >Maintenant, faites une comparaison et une explication des méthodes d'épissage de chaînes suivantes :
1 res = strA.strB et res = "strAstrB"
Dans ce cas, zend ré-allouera un morceau de mémoire et le traitera en conséquence. , sa vitesse est moyenne.
2 strA = strA.strB
C'est le plus rapide, zend effectuera directement une relocalisation en fonction du strA actuel pour éviter les copies répétées
3 res = intA.intB
C'est plus lent, car conversion de format implicite est requis, vous devez également faire attention à l'éviter lors de l'écriture de programmes
4 strA = sprintf (« %s%s », strA, strB
Ce sera la méthode la plus lente, car sprintf n'est pas une méthode structure du langage en PHP, et il faut beaucoup de temps pour identifier et traiter le format. De plus, le mécanisme lui-même est malloc. Cependant, la méthode sprintf est la plus lisible et, en pratique, elle peut être choisie de manière flexible en fonction de circonstances spécifiques.

5.2.3 Variables du tableau
Le tableau de PHP est naturellement implémenté via Zend Hash Table.

Comment implémenter l'opération foreach ? Foreach d'un tableau est complété en parcourant la liste doublement chaînée dans la table de hachage. Pour les tableaux d'index, le parcours via foreach est beaucoup plus efficace que for, éliminant le besoin de rechercher clé->valeur. L’opération de comptage appelle directement l’opération HashTable->NumOfElements, O(1). Pour une chaîne comme « 123 », zend la convertira sous sa forme entière. arr['123'] et arr[123]

5.3 Gestion des variables PHP - comptage de références et copie sur écriture
Le comptage de références est largement utilisé dans le recyclage de la mémoire, les opérations sur les chaînes, etc. Le comptage de références de Zval est implémenté via les variables membres is_ref et ref_count. Grâce au comptage de références, plusieurs variables peuvent partager les mêmes données. Évitez la consommation énorme causée par des copies fréquentes. Lors de l'exécution d'une opération d'affectation sur

, zend pointe la variable vers les mêmes zval et ref_count Lors de l'exécution d'une opération non définie, le ref_count-1 correspondant est utilisé. L'opération de destruction ne sera effectuée que lorsque ref_count sera réduit à 0. S'il s'agit d'une affectation de référence, zend modifiera is_ref en 1.

Les variables PHP réalisent le partage de données variables grâce au comptage de références. Que se passe-t-il si l'une des valeurs de variable est modifiée ? Lorsque vous essayez d'écrire une variable, si Zend constate que le zval pointé par la variable est partagé par plusieurs variables, il copiera un zval avec un ref_count de 1 et décrémentera le refcount du zval d'origine. Ce processus est appelé "séparation zval". ". On peut voir que zend n'effectue des opérations de copie que lorsqu'une opération d'écriture se produit, elle est donc également appelée

copie sur écriture (copie sur écriture)

Pour les variables de référence, son exigences et non-référence Au contraire, les

variables assignées par référence doivent être regroupées. La modification d'une variable modifie toutes les variables regroupées.

5.4 Implémentation des variables locales et des variables globales en PHP :
Comment les variables locales et les variables globales sont-elles implémentées en PHP ? Pour une requête, PHP peut voir

deux tables de symboles (symbol_table et active_symbol_table) à tout moment, dont la première est utilisée pour maintenir les variables globales. Ce dernier est un pointeur pointant vers la table de symboles variable actuellement active Lorsque le programme entre dans une fonction, zend lui allouera une table de symboles x et pointera active_symbol_table vers a. De cette manière, la distinction entre les variables globales et locales est réalisée.

Obtenir les valeurs des variables : la table des symboles de PHP est implémentée via hash_table. Chaque variable se voit attribuer un identifiant unique lors de l'obtention, le zval correspondant est trouvé dans la table en fonction de l'identifiant et renvoyé.

Utiliser des variables globales dans les fonctions : Dans les fonctions, nous pouvons utiliser des variables globales en déclarant explicitement global.

Créez une référence à la variable du même nom dans symbol_table dans active_symbol_table (si la valeur de la variable de référence doit être mise à jour, tout le monde la mettra à jour ensemble s'il n'y a pas de variable du même nom dans). symbol_table, il sera créé en premier.

Référence :

  • http://www.php.cn/

  • http://www.php.cn/

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


Principe d'exécution de PHP

php est un langage avec une application très simple et une efficacité de développement extrêmement élevée. Ses variables faiblement typées peuvent éviter aux programmeurs de définir un grand nombre de variables. effort de conversion de type, etc. C'est un langage dynamique adapté au développement Web.

1. Principes et caractéristiques de la conception PHP

  • Modèle multi-processus : cela peut garantir que les processus ne sont pas affectés les uns par les autres et que l'utilisation des ressources des processus est plus rapide et plus pratique

  • Langage faiblement typé : contrairement aux langages fortement typés tels que C, C, Java et d'autres langages, le type de variables en PHP n'est pas déterminé au début, il est déterminé au moment de l'exécution, il peut être converti en type implicitement ou explicitement, ce qui le rend très flexible dans le développement. Les programmeurs n'ont pas besoin de prêter attention au problème de type variable

  • Composant du moteur Zend. Le mode (ext ) réduit le couplage interne

  • La couche intermédiaire (sapi) isole le serveur web et php

  • La syntaxe est simple et flexible, avec peu de spécifications. Cela présente des avantages et des inconvénients. . .

2. Le système à quatre couches de PHP

PHP执行原理

php a un total de système à quatre couches de haut en bas :

  • Zend Engine : Zend est entièrement implémenté en C et est la partie centrale de PHP. Il traduit le code PHP en opcode exécutable, traite et implémente les méthodes de traitement correspondantes (principe : Le blog de Brother Niao), implémente les structures de données de base, l'allocation et la gestion de la mémoire, et fournit les méthodes API correspondantes pour une utilisation externe, qui sont au cœur de tout.

  • Extensions : Autour du moteur Zend, les extensions fournissent divers services de base via des composants couramment utilisés, des tableaux de fonctions intégrés, des bibliothèques standard, etc. Les utilisateurs peuvent également implémenter leurs propres extensions si nécessaire pour réaliser une expansion fonctionnelle et à d'autres fins. Par exemple, la couche intermédiaire PHP et l'analyse de texte enrichi actuellement utilisées par Tieba sont des applications typiques des extensions).

  • Sapi : Le nom complet de Sapi est Server Application Programing Interface, qui est l'interface de programmation d'applications serveur qui permet à PHP d'interagir avec les données périphériques via une série de hooks. Fonctions. Il s'agit d'une conception très élégante et réussie de PHP. Grâce à sapi, PHP lui-même est découplé et isolé avec succès de l'application de couche supérieure. PHP ne peut plus considérer comment être compatible avec différentes applications, et l'application elle-même peut également implémenter. traitement différent selon ses propres caractéristiques.

  • Application de couche supérieure : Il s'agit du programme d'application écrit par les programmeurs. Différents modes d'application sont obtenus via différentes méthodes sapi, telles que la mise en œuvre d'applications Web via un serveur Web, exécuter en tant que script sur la ligne de commande, etc.

3 Sapi

Comme mentionné précédemment, Sapi permet aux applications externes de communiquer avec php via une série d'interfaces de données. peuvent être échangées et des méthodes de traitement spécifiques peuvent être implémentées en fonction de différentes caractéristiques de l'application :

  • apache2handler : en utilisant Apache comme serveur Web, la méthode de traitement lors de l'exécution en mode MOD_PHP est également. maintenant Le plus largement utilisé

  • cgi : Il s'agit d'un autre moyen d'interaction entre le serveur Web et php, qui est le protocole fastcgi

  • cli : Mode d'application de débogage des commandes

4. Processus d'exécution du code PHP

PHP执行原理

Comme le montre la figure, php est implémenté via le Moteur Zend Un processus d'exécution de langage dynamique typique est décrit : un morceau de code est obtenu, et après une analyse lexicale, une analyse syntaxique et d'autres étapes, le programme source est traduit en instructions (opcodes), puis la machine virtuelle Zend exécute ces instructions séquentiellement . PHP lui-même est implémenté en langage C, donc les fonctions finalement appelées sont également des fonctions en langage C.

Le cœur de l'exécution de PHP est constitué des instructions traduites une par une, c'est-à-dire opcode

L'opcode est l'unité la plus basique de l'exécution d'un programme PHP. Un opcode se compose de deux paramètres (op1, op2), d'une valeur de retour et d'une fonction de traitement. Le programme PHP se traduit finalement par l'exécution séquentielle d'un ensemble de fonctions de traitement d'opcodes.

Plusieurs fonctions couramment utilisées :

  • END_ASSIGN_SPEC_CV_CV_HANDLER : allocation de variable (a=b)

  • ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER : appel de fonction

  • ZEND_CONCAT_SPEC_CV_CV_HANDLER : Concaténation de chaînes a.b

  • ZEND_ADD_SPEC_CV_CONST_HANDLER : Ajout d'un 2

  • ZEND_ IS_EQUAL_SPEC_CV _CONST : égalité de jugement a ==1

  • ZEND_IS_IDENTICAL_SPEC_CV_CONST : Déterminer l'égalité a===1

5. Introduction au moteur Zend

Zend Le moteur est le cœur de php. Les principaux mécanismes de conception sont :

5.1 Implémentation de la structure de données HashTable

HashTable est la structure de données de base de Zend. Elle est utilisée pour implémenter presque toutes les fonctions de php. PHP data array() est une application typique. De plus, dans Zend, des fonctions telles que les tables de symboles de fonction et les variables panoramiques sont implémentées via HashTable.

La table de hachage Zend implémente une structure de hachage de table de hachage typique et fournit en même temps les fonctions de parcours avant, arrière et de tableau en attachant une liste chaînée bidirectionnelle. La structure est la suivante :

PHP执行原理

Comme vous pouvez le voir, la table de hachage a à la fois une structure de hachage sous forme de clé->valeur et un mode de liste doublement chaînée, ce qui la rend très pratique pour prendre en charge la recherche rapide et le parcours linéaire.


Structure de hachage  : La structure de hachage de Zend est un modèle de table de hachage typique, qui résout les conflits via une liste chaînée. Il convient de noter que la table de hachage de Zend est une structure de données à croissance automatique Lorsque le nombre de tables de hachage est plein, elle s'étendra dynamiquement de 2 fois et repositionnera les éléments. La taille initiale est de 8. De plus, lors de l'exécution d'une recherche rapide clé->valeur, zend lui-même a également apporté quelques optimisations pour accélérer le processus en échangeant de l'espace contre du temps. Par exemple, une variable nKeyLength est utilisée dans chaque élément pour identifier la longueur de la clé pour une détermination rapide.
Liste chaînée double : la table de hachage Zend implémente un parcours linéaire d'éléments via une structure de liste chaînée. Théoriquement, il suffit d'utiliser une liste chaînée unidirectionnelle pour le parcours. L'objectif principal de l'utilisation d'une liste doublement chaînée est de supprimer rapidement et d'éviter le parcours. La table de hachage Zend est une structure composite lorsqu'elle est utilisée comme tableau, elle prend en charge les tableaux associatifs communs et peut également être utilisée comme numéros d'index séquentiels, et permet même un mélange des deux.
Tableau associatif PHP : Le tableau associatif est une application hash_table typique. Un processus de requête passe par les étapes suivantes (comme le montre le code, il s'agit d'un processus de requête de hachage courant et quelques jugements rapides sont ajoutés pour accélérer la recherche) :

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 tableau d'index : Le tableau d'index est notre tableau commun, accessible via des indices. Par exemple, arr[0], Zend HashTable a été normalisé en interne, et la clé de type d'index se voit également attribuer une valeur de hachage et nKeyLength (0). La variable membre interne nNextFreeElement est l'identifiant maximum actuellement attribué, qui est automatiquement augmenté de un après chaque poussée. C'est ce processus de normalisation qui permet à PHP de réaliser un mélange de données associatives et non associatives. En raison de la particularité de l'opération push, l'ordre des clés d'index dans le tableau PHP n'est pas déterminé par la taille de l'indice, mais par l'ordre du push. Par exemple, arr[1] = 2; arr[2] = 3; pour une clé de type double, Zend HashTable la traitera comme une clé d'index

5.2 Principe d'implémentation des variables PHP

PHP est un langage faiblement typé et ne distingue pas strictement les types de variables. Les variables PHP peuvent être divisées en types simples (int, sting, bool), types de collection (tableau, ressource, objet) et constantes (const). Toutes les variables ont la même structure en bas

zval.

zval est une structure de données très importante dans zend, utilisée pour marquer et implémenter des variables PHP. Sa structure de données est la suivante :

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;
Parmi elles,

    <.>
  • zval_value value

    est la valeur réelle de la variable, en particulier une union zvalue_value :

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

    est un compteur utilisé pour enregistrer le nombre de variables (ou symboles, symboles) pointant vers le zval. Lorsque la variable est générée, son refcount=1. Les opérations d'affectation typiques telles que $a = $b augmenteront le refcount de zval de 1, et l'opération de non-définition le diminuera de 1 en conséquence. Avant PHP5.3, le mécanisme de comptage de références était utilisé pour implémenter GC Si le refcount d'un zval était inférieur à 0, le moteur Zend penserait qu'il n'y avait aucune variable pointant vers le zval, et libérerait donc l'espace mémoire occupé par. le zval. Mais parfois, les choses ne sont pas si simples. Nous verrons plus tard que le simple mécanisme de comptage de références ne peut pas GC le zval référencé circulairement, même si la variable pointant vers le zval a été non définie, ce qui entraîne une fuite de mémoire (Memory Leak).

  • type zend_uchar

    Ce champ est utilisé pour indiquer le type réel de la variable. Les variables en PHP incluent quatre types scalaires (bool, int, float, string), deux types composites (tableau, objet) et deux types spéciaux (ressource et NULL). Dans zend, ces types correspondent aux macros suivantes (emplacement du code 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

    Ceci Le champ est utilisé pour indiquer si la variable est une variable de référence. Pour les variables ordinaires, la valeur est 0 et pour les variables de référence, la valeur est 1. Cette variable affectera le partage, la séparation, etc. de zval

5.2.1 Variables entières et à virgule flottante

Les nombres entiers et à virgule flottante sont l'un des types de base en PHP et sont également des variables simples. Pour les entiers et les nombres à virgule flottante, les valeurs correspondantes sont stockées directement dans zvalue. Leurs types sont respectivement longs et doubles.
Comme le montre la structure zvalue, pour les types entiers, contrairement aux langages fortement typés tels que C, PHP ne fait pas de distinction entre les types int, int non signé, long, long long et autres. entiers uniquement Un type est long. De là, on peut voir qu'en PHP, la plage de valeurs des entiers est déterminée par le nombre de bits du compilateur et n'est pas fixe. Que se passe-t-il si un entier sort des limites en php ? PHP convertira automatiquement les entiers en types à virgule flottante

Pour les nombres à virgule flottante, similaires aux entiers, il ne fait pas de différence entre float et double mais n'unifie qu'un seul type : double

5.2.2 Variables de caractères

Comme les entiers, les variables de caractères sont également des types de base et des variables simples en PHP. La structure zvalue montre qu'en PHP, une chaîne est composée d'un pointeur vers les données réelles et d'une structure de longueur, similaire à la chaîne en C. Puisque la longueur est représentée par une variable réelle, contrairement à c, sa chaîne peut être une donnée binaire (y compris 0). En même temps, en PHP, trouver la longueur de la chaîne strlen est une opération O(1)

. Méthodes courantes d'épissage de chaînes et comparaison de vitesse :

Supposons qu'il existe les 4 variables suivantes : strA='123'; strB = '456'; >Maintenant, faites une comparaison et une explication des méthodes d'épissage de chaînes suivantes :
1 res = strA.strB et res = "strAstrB"
Dans ce cas, zend ré-allouera un morceau de mémoire et le traitera en conséquence. , sa vitesse est moyenne.
2 strA = strA.strB
C'est le plus rapide, zend effectuera directement une relocalisation en fonction du strA actuel pour éviter les copies répétées
3 res = intA.intB
C'est plus lent, car conversion de format implicite est requis, vous devez également faire attention à l'éviter lors de l'écriture de programmes
4 strA = sprintf (« %s%s », strA, strB
Ce sera la méthode la plus lente, car sprintf n'est pas une méthode structure du langage en PHP, et il faut beaucoup de temps pour identifier et traiter le format. De plus, le mécanisme lui-même est malloc. Cependant, la méthode sprintf est la plus lisible et, en pratique, elle peut être choisie de manière flexible en fonction de circonstances spécifiques.

5.2.3 Variables du tableau
Le tableau de PHP est naturellement implémenté via Zend Hash Table.

Comment implémenter l'opération foreach ? Foreach d'un tableau est complété en parcourant la liste doublement chaînée dans la table de hachage. Pour les tableaux d'index, le parcours via foreach est beaucoup plus efficace que for, éliminant le besoin de rechercher clé->valeur. L’opération de comptage appelle directement l’opération HashTable->NumOfElements, O(1). Pour une chaîne comme « 123 », zend la convertira sous sa forme entière. arr['123'] et arr[123]

5.3 Gestion des variables PHP - comptage de références et copie sur écriture
Le comptage de références est largement utilisé dans le recyclage de la mémoire, les opérations sur les chaînes, etc. Le comptage de références de Zval est implémenté via les variables membres is_ref et ref_count. Grâce au comptage de références, plusieurs variables peuvent partager les mêmes données. Évitez la consommation énorme causée par des copies fréquentes. Lors de l'exécution d'une opération d'affectation sur

, zend pointe la variable vers les mêmes zval et ref_count Lors de l'exécution d'une opération non définie, le ref_count-1 correspondant est utilisé. L'opération de destruction ne sera effectuée que lorsque ref_count sera réduit à 0. S'il s'agit d'une affectation de référence, zend modifiera is_ref en 1.

Les variables PHP réalisent le partage de données variables grâce au comptage de références. Que se passe-t-il si l'une des valeurs de variable est modifiée ? Lorsque vous essayez d'écrire une variable, si Zend constate que le zval pointé par la variable est partagé par plusieurs variables, il copiera un zval avec un ref_count de 1 et décrémentera le refcount du zval d'origine. Ce processus est appelé "séparation zval". ". On peut voir que zend n'effectue des opérations de copie que lorsqu'une opération d'écriture se produit, elle est donc également appelée

copie sur écriture (copie sur écriture)

Pour les variables de référence, son exigences et non-référence Au contraire, les

variables assignées par référence doivent être regroupées. La modification d'une variable modifie toutes les variables regroupées.

5.4 Implémentation des variables locales et des variables globales en PHP :
Comment les variables locales et les variables globales sont-elles implémentées en PHP ? Pour une requête, PHP peut voir

deux tables de symboles (symbol_table et active_symbol_table) à tout moment, dont la première est utilisée pour maintenir les variables globales. Ce dernier est un pointeur pointant vers la table de symboles variable actuellement active Lorsque le programme entre dans une fonction, zend lui allouera une table de symboles x et pointera active_symbol_table vers a. De cette manière, la distinction entre les variables globales et locales est réalisée.

Obtenir les valeurs des variables : la table des symboles de PHP est implémentée via hash_table. Chaque variable se voit attribuer un identifiant unique lors de l'obtention, le zval correspondant est trouvé dans la table en fonction de l'identifiant et renvoyé.

Utiliser des variables globales dans les fonctions : Dans les fonctions, nous pouvons utiliser des variables globales en déclarant explicitement global.

Créez une référence à la variable du même nom dans symbol_table dans active_symbol_table (si la valeur de la variable de référence doit être mise à jour, tout le monde la mettra à jour ensemble s'il n'y a pas de variable du même nom dans). symbol_table, il sera créé en premier.

Pour plus de principes d'exécution PHP et d'articles connexes, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn