Maison  >  Article  >  développement back-end  >  Introduction détaillée au principe de fonctionnement sous-jacent de PHP

Introduction détaillée au principe de fonctionnement sous-jacent de PHP

王林
王林original
2019-09-02 13:13:174560parcourir

Introduction détaillée au principe de fonctionnement sous-jacent de PHP

PHP est un langage dynamique adapté au développement web. Pour être plus précis, il s'agit d'un framework logiciel qui utilise le langage C pour implémenter un grand nombre de modules de composants. Il s'agit d'un cadre d'interface utilisateur puissant.

En bref ; processus d'exécution dynamique du langage PHP : après avoir obtenu un morceau de code, après analyse lexicale, analyse syntaxique et autres étapes, le programme source sera traduit en instructions (opcodes), puis en machine virtuelle ZEND. exécutera ces instructions une fois pour terminer l’opération. PHP lui-même est implémenté en C, donc les fonctions finalement appelées sont également des fonctions C. En fait, on peut considérer PHP comme un logiciel développé en C.

1. Le concept de conception et les caractéristiques de PHP

1. Modèle multi-processus : Puisque PHP est un modèle multi-processus, différentes requêtes ne le font pas. interférer les uns avec les autres, il est donc garanti que l'échec d'une requête n'affectera pas l'ensemble du service. Actuellement, PHP prend déjà en charge le modèle multithread.

2. Langage faiblement typé : Contrairement au C/C++, JAVA, C# et d'autres langages, PHP est un langage faiblement typé. Le type d'une variable n'est pas déterminé au début. Il est déterminé lors du fonctionnement et une conversion de type implicite ou explicite peut se produire. La flexibilité de ce mécanisme est très pratique et efficace dans le développement Web. Les détails seront discutés plus tard dans les variables PHP. sont détaillés dans.

3. Le modèle moteur (Zend) + composant (ext) réduit le couplage interne.

4. La couche intermédiaire (sapi) Le nom complet de Sapi est Server Application Programming Interface, qui isole le serveur web et PHP.

5. La syntaxe est simple et flexible, sans trop de spécifications. Les inconvénients conduisent à un mélange de styles.

2. Le système à quatre couches de PHP

L'architecture de base de PHP est la suivante :

Introduction détaillée au principe de fonctionnement sous-jacent de PHP

PHP est un 4- système de couches de bas en haut Système :

1. Moteur Zend : Zend est entièrement implémenté en C pur et est la partie centrale de PHP. Il traduit le code PHP (lexical, analyse syntaxique et autres processus de compilation) en exécutable. Traitement et implémentation de l'opcode Les méthodes de traitement correspondantes, l'implémentation de structures de données de base (telles que la table de hachage, OO), le mécanisme et la gestion d'allocation de mémoire, et la fourniture de méthodes API correspondantes pour les appels externes sont au cœur de tout. Toutes les fonctions périphériques sont implémentées autour de Zend.

2. Extensions : autour du moteur Zend, les extensions fournissent divers services de base basés sur des composants. Nos diverses fonctions intégrées communes (séries de tableaux), bibliothèques standard, etc. sont toutes implémentées via des extensions. Utilisateurs Vous pouvez également implémenter des applications typiques de votre propre extension selon vos besoins).

3. Sapi : Le nom complet de Sapi est Server Application Programming Interface, qui est l'interface de programmation d'application serveur. Sapi utilise une série de fonctions de hook pour permettre à PHP d'interagir avec les données périphériques. et une conception réussie de PHP.Grâce à sapi, PHP lui-même est découplé et isolé avec succès des applications 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 différentes méthodes de traitement selon ses propres. caractéristiques.

4. Application de couche supérieure : il s'agit du programme PHP que nous écrivons habituellement. Nous obtenons différents modes d'application via différentes méthodes spai, comment implémenter des applications Web via un serveur Web, les exécuter en mode script sur la ligne de commande. etc. attendez.

Il nous faut : un moteur performant (Zend) + les bonnes roues (Ext) + la bonne chenille (Sapi).

3. Sapi

Sapi permet aux applications externes d'échanger des données avec PHP via une série d'interfaces et de mettre en œuvre des méthodes de traitement spécifiques en fonction de différentes caractéristiques d'application :

.

1. apache2handler : il s'agit de la méthode de traitement lors de l'utilisation d'Apache comme serveur Web et de l'exécution en mode mod_PHP. C'est également la méthode la plus utilisée actuellement.

2. cgi : Il s'agit d'une autre méthode d'interaction directe entre le serveur Web et PHP, qui est le célèbre protocole fastcgi. Récemment, fastcgi+PHP a été de plus en plus utilisé, et c'est également le seul pris en charge par l'asynchrone. méthode du serveur Web ; le serveur nginx d’application typique ; fastcgi est simplement une extension de php.

Charger le gestionnaire de processus FastCGI (IIS ISAPI ou Module Apache) au démarrage du serveur Web

Le gestionnaire de processus FastCGI s'initialise et démarre plusieurs processus interpréteurs CGI (visibles plusieurs php-cgi ) et attendez pour la connexion depuis le serveur Web.

Lorsqu'une requête client atteint le serveur Web, le gestionnaire de processus FastCGI sélectionne et se connecte à un interpréteur CGI. Le serveur Web envoie des variables d'environnement CGI et des entrées standard au sous-processus FastCGI php-cgi.

Une fois le sous-processus FastCGI terminé, il renvoie la sortie standard et les informations d'erreur au serveur Web à partir de la même connexion. Lorsque le processus enfant FastCGI ferme la connexion, la demande est traitée. Le processus enfant FastCGI attend et gère ensuite la prochaine connexion du gestionnaire de processus FastCGI (exécuté sur le serveur Web). En mode CGI, php-cgi se termine à ce stade.

Dans le cas ci-dessus, vous pouvez imaginer à quel point CGI est généralement lent. Chaque requête Web adressée à PHP doit réanalyser php.ini, recharger toutes les extensions et réinitialiser toutes les structures de données. Avec FastCGI, tout cela ne se produit qu’une seule fois, au démarrage du processus. Un avantage supplémentaire est que les connexions persistantes aux bases de données fonctionnent.

Introduction détaillée au principe de fonctionnement sous-jacent de PHP

Introduction détaillée au principe de fonctionnement sous-jacent de PHP

3. cli : mode application appelé par ligne de commande

Interface de ligne de commande (anglais : interface de ligne de commande, abréviation : CLI) est l'interface utilisateur la plus largement utilisée avant la popularité des interfaces utilisateur graphiques. Elle ne prend généralement pas en charge la souris. L'utilisateur saisit les instructions via le clavier et l'ordinateur exécute les instructions après les avoir reçues. Certaines personnes l'appellent également Character User Interface (CUI).
On pense généralement que l'interface de ligne de commande (CLI) n'est pas aussi conviviale que l'interface utilisateur graphique (GUI). Étant donné que le logiciel d'interface de ligne de commande nécessite généralement que l'utilisateur mémorise les commandes de fonctionnement, cependant, en raison de ses propres caractéristiques, l'interface de ligne de commande économise les ressources du système informatique par rapport à l'interface utilisateur graphique. Dans l'hypothèse de la mémorisation des commandes, l'utilisation de l'interface de ligne de commande est souvent plus rapide que l'utilisation de l'interface utilisateur graphique. Par conséquent, les systèmes d'exploitation dotés d'interfaces utilisateur graphiques conservent des interfaces de ligne de commande facultatives.

4. Processus d'exécution du langage PHP

Introduction détaillée au principe de fonctionnement sous-jacent de PHP

Processus d'exécution du langage dynamique PHP : après avoir obtenu un morceau de code, après analyse lexicale, grammaire Après l'analyse et d'autres étapes, le programme source sera traduit en instructions (opcodes), puis la machine virtuelle ZEND exécutera ces instructions dans l'ordre pour terminer l'opération. PHP lui-même est implémenté en C, donc les fonctions finalement appelées sont également des fonctions C. En fait, on peut considérer PHP comme un logiciel développé en C.

Le cœur de l'exécution de PHP réside dans les instructions traduites, qui sont également des opcodes.

L'Opcode est l'unité la plus basique de l'exécution d'un programme PHP.

Dans le domaine de l'informatique, le code d'opération (OPCode) est utilisé pour décrire les instructions en langage machine, spécifiant la partie du code machine pour effectuer une certaine opération. Le format d'instruction et les spécifications qui constituent l'OPCode sont traités par. spécifié par la spécification d’instruction de l’appareil.

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 de traitement courantes :

ZEND_ASSIGN_SPEC_CV_CV_HANDLER : 变量分配 ($a=$b)
ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER:函数调用
ZEND_CONCAT_SPEC_CV_CV_HANDLER:字符串拼接 $a.$b
ZEND_ADD_SPEC_CV_CONST_HANDLER: 加法运算 $a+2
ZEND_IS_EQUAL_SPEC_CV_CONST:判断相等 $a==1
ZEND_IS_IDENTICAL_SPEC_CV_CONST:判断相等 $a===1

5. Structure de données HashTable-core

HashTable est la structure de données de base de Zend In. PHP, il est utilisé pour implémenter presque toutes les fonctions courantes.Le tableau PHP que nous connaissons est son application typique, de plus, dans zend, comme la table des symboles de fonction, les variables globales, etc. sont également basées sur la table de hachage et ont les caractéristiques suivantes. :

1. Prend en charge les requêtes clé>valeur typiques

2 Peut être utilisé comme un tableau

3 L'ajout et la suppression de nœuds sont d'une complexité O(1). 🎜>

4. La clé prend en charge les types mixtes : le tableau d'index de combinaison de nombres associé

existe en même temps 5. La valeur prend en charge les types mixtes : array("string",2332)

6. Prend en charge le parcours linéaire : comme foreach

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

Introduction détaillée au principe de fonctionnement sous-jacent de PHP

Vous pouvez voir qu'il existe à la fois des structures de hachage clé->valeur et des modes de liste doublement chaînés dans la table de hachage, ce qui la rend très pratique. recherche rapide et parcours linéaire.

1. 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.

2. Liste doublement chaînée : 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.) :

getKeyHashValue h;
index = n & nTableMask;
Bucket *p = arBucket[index];
while (p) {
       if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
              RETURN p->data;   
        }
        p=p->next;
}
RETURN FALTURE;

4、PHP索引数组:索引数组就是我们常见的数组,通过下标访问。例如 $arr[0],Zend HashTable内部进行了归一化处理,对于index类型key同样分配了hash值和nKeyLength(为0)。内部成员变量 nNextFreeElement就是当前分配到的最大id,每次push后自动加一。正是这种归一化处理,PHP才能够实现关联和非关联的混合。由于 push操作的特殊性,索引key在PHP数组中先后顺序并不是通过下标大小来决定,而是由push的先后决定。例如 $arr[1] = 2; $arr[2] = 3;对于double类型的key,Zend HashTable会将他当做索引key处理。

六、Hash Table变量

PHP是一门弱类型语言,本身不严格区分变量的类型。PHP在变量申明的时候不需要指定类型。

PHP在程序运行期间可能进行变量类型的隐示转换。 和其他强类型语言一样,程序中也可以进行显示的类型转换。

PHP变量可以分为简单类型(int、string、bool)、集合类型(array resource object)和常量(const)。以上所有的变量在底层都是同一种结构 zval。

Zval主要由三部分组成:

type:指定了变量所述的类型(整数、字符串、数组等)

refcount&is_ref:用来实现引用计数(后面具体介绍)

value:核心部分,存储了变量的实际数据

Zvalue是用来保存一个变量的实际数据。因为要存储多种类型,所以zvalue是一个union,也由此实现了弱类型。

引用计数在内存回收、字符串操作等地方使用非常广泛。PHP中的变量就是引用计数的典型应用。Zval的引用计数通过成员变量is_ref和ref_count实现,通过引用计数,多个变量可以共享同一份数据。避免频繁拷贝带来的大量消耗。在进行赋值操作时,zend将变量指向相同的zval同时ref_count++,在unset操作时,对应的ref_count-1。只有ref_count减为0时才会真正执行销毁操作。如果是引用赋值,则zend会修改is_ref为1。

PHP变量通过引用计数实现变量共享数据,那如果改变其中一个变量值呢?当试图写入一个变量时,Zend若发现该变量指向的zval被多个变量共 享,则为其复制一份ref_count为1的zval,并递减原zval的refcount,这个过程称为“zval分离”。可见,只有在有写操作发生时 zend才进行拷贝操作,因此也叫copy-on-write(写时拷贝)对于引用型变量,其要求和非引用型相反,引用赋值的变量间必须是捆绑的,修改一个变量就修改了所有捆绑变量。整数、浮点数是PHP中的基础类型之一,也是一个简单型变量。对于整数和浮点数,在zvalue中直接存储对应的值。其类型分别是long和double。

从zvalue结构中可以看出,对于整数类型,和c等强类型语言不同,PHP是不区分int、unsigned int、long、long long等类型的,对它来说,整数只有一种类型也就是long。由此,可以看出,在PHP里面,整数的取值范围是由编译器位数来决定而不是固定不变的。

对于浮点数,类似整数,它也不区分float和double而是统一只有double一种类型。在PHP中,如果整数范围越界了怎么办?这种情况下会自动转换为double类型,这个一定要小心,很多trick都是由此产生。

和整数一样,字符变量也是PHP中的基础类型和简单型变量。通过zvalue结构可以看出,在PHP中,字符串是由由指向实际数据的指针和长度结 构体组成,这点和c++中的string比较类似。由于通过一个实际变量表示长度,和c不同,它的字符串可以是2进制数据(包含\0),同时在PHP中, 求字符串长度strlen是O(1)操作。在新增、修改、追加字符串操作时,PHP都会重新分配内存生成新的字符串。最后,出于安全考虑,PHP在生成一个字符串时末尾仍然会添加\0。

常见的字符串拼接方式及速度比较:假设有如下4个变量:$strA=‘123’; $strB = ‘456’; $intA=123; intB=456;

现在对如下的几种字符串拼接方式做一个比较和说明:

$res = $strA.$strB和$res = “$strA$strB”
这种情况下,zend会重新malloc一块内存并进行相应处理,其速度一般
$strA = $strA.$strB
这种是速度最快的,zend会在当前strA基础上直接relloc,避免重复拷贝
$res = $intA.$intB
这种速度较慢,因为需要做隐式的格式转换,实际编写程序中也应该注意尽量避免
$strA = sprintf (“%s%s”,$strA.$strB);
这会是最慢的一种方式,因为sprintf在PHP中并不是一个语言结构,本身对于格式识别和处理就需要耗费比较多时间,另外本身机制

也是malloc内存。不过sprintf的方式最具可读性,实际中可以根据具体情况灵活选择。

PHP的数组通过Zend HashTable来天然实现。foreach操作如何实现?对一个数组的foreach就是通过遍历hashtable中的双向链表完成。对于索引数组,通过foreach遍 历效率比for高很多,省去了key->value的查找。count操作直接调用 HashTable->NumOfElements,O(1)操作。对于’123’这样的字符串,zend会转换为其整数形 式。$arr[‘123’]和$arr[123]是等价的

La variable de type ressource est la variable la plus complexe en PHP et est également une structure composite. Le zval de PHP peut représenter un large éventail de types de données, mais il est difficile de décrire entièrement les types de données personnalisés. Puisqu’il n’existe aucun moyen efficace de représenter ces structures composites, il n’existe aucun moyen d’utiliser des opérateurs traditionnels sur celles-ci. Pour résoudre ce problème, il vous suffit de faire référence au pointeur via un identifiant (étiquette) essentiellement arbitraire, appelé ressource.

Dans zval, pour ressource, lval est utilisé comme pointeur, pointant directement vers l'adresse de la ressource. La ressource peut être n'importe quelle structure composite. Les noms familiers mysqli, fsock, memcached, etc. sont tous des ressources.

Comment utiliser les ressources :

Inscription : Pour un type de données personnalisé, vous souhaitez l'utiliser comme ressource. Tout d’abord, vous devez l’enregistrer et Zend lui attribuera un identifiant globalement unique.

Obtenir une variable de ressource : pour les ressources, zend maintient un id->hash_tale des données réelles. Pour une ressource, seul son identifiant est enregistré dans zval. Lors de la récupération, recherchez la valeur spécifique dans hash_table via l'identifiant et renvoyez-la.

Destruction des ressources : les types de données des ressources sont divers. Zend lui-même n'a aucun moyen de le détruire. Par conséquent, les utilisateurs doivent fournir une fonction de destruction lors de l’enregistrement des ressources.
Lorsque les ressources sont désactivées, zend appelle la fonction correspondante pour terminer la destruction. Supprimez-le également de la table des ressources globales.

Les ressources peuvent persister à long terme, non seulement après que toutes les variables qui y font référence sont hors de portée, mais même après la fin d'une requête et une nouvelle requête est effectuée. Ces ressources sont appelées ressources persistantes car elles persistent tout au long du cycle de vie du SAPI, sauf destruction spécifique. Dans de nombreux cas, les ressources persistantes peuvent améliorer les performances dans une certaine mesure. Par exemple, dans notre mysql_pconnect commun, les ressources persistantes allouent de la mémoire via pemalloc afin qu'elles ne soient pas libérées à la fin de la requête. Pour Zend, il n'y a pas de distinction entre les deux en soi.

Comment les variables locales et 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, la première étant utilisée pour gérer 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 et renvoyé en fonction de l'identifiant.

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. S'il n'y a pas de variable du même nom dans symbol_table, elle sera créée en premier.

Tutoriel vidéo de site Web PHP chinois recommandé : Tutoriel vidéo PHP

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en 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