On dit que PHP est simple, mais il n'est pas facile de le maîtriser. En plus de pouvoir l’utiliser, nous devons également connaître son principe de fonctionnement sous-jacent.
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 composants. Dans un sens plus étroit, il peut être considéré comme un puissant cadre d’interface utilisateur.
Quel est le but de comprendre l’implémentation sous-jacente de PHP ? Si vous souhaitez bien utiliser le langage dynamique, vous devez d'abord le comprendre. La gestion de la mémoire et les modèles de framework valent la peine d'être appris. Grâce à l'expansion et au développement, nous pouvons obtenir des fonctions de plus en plus puissantes et optimiser les performances de nos programmes.
1. Concept et caractéristiques de conception PHP
Modèle multi-processus : PHP étant un modèle multi-processus, les différentes requêtes n'interfèrent pas les unes avec les autres, ce qui garantit cette requête sera suspendue. La perte n'affectera pas le service global. Bien entendu, avec l'évolution des temps, PHP a déjà pris en charge le modèle multi-thread. Langage faiblement typé : contrairement à 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. Le modèle moteur (Zend) + composant (ext) réduit le couplage interne. La couche intermédiaire (sapi) isole le serveur web et PHP. La syntaxe est simple et flexible, sans trop de spécifications. Les lacunes conduisent à des styles mixtes, mais peu importe à quel point un programmeur est mauvais, il n'écrira pas un programme trop scandaleux et qui mettrait en danger la situation globale.
2. Le système à quatre couches de PHP
L'architecture de base de PHP est la suivante :
Sur l'image, on peut voir que PHP est un système à 4 couches de bas en haut :
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, etc.) Le processus de compilation) traite les opcodes exécutables et implémente les méthodes de traitement correspondantes, implémente les structures de données de base (telles que la table de hachage, oo), l'allocation et la gestion de la mémoire, et fournit les méthodes API correspondantes pour les appels externes. de tout. Les fonctions périphériques sont toutes implémentées autour de Zend. Extensions : centrées sur le moteur Zend, les extensions fournissent divers services de base basés sur des composants. Nos diverses fonctions intégrées communes (telles que les séries de tableaux), nos bibliothèques standard, etc. sont toutes implémentées via des extensions. posséder l'extension selon les besoins pour réaliser l'expansion des fonctions, l'optimisation des performances 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 de l'extension). Sapi : Le nom complet de Sapi est Server Application Programming 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 fonctions de hook. Il s'agit d'une conception très élégante et réussie de PHP via sapi. PHP peut être intégré avec succès dans Puisqu'il est découplé et isolé des applications de couche supérieure, PHP ne peut plus réfléchir à la manière d'être compatible avec différentes applications, et l'application elle-même peut également implémenter différentes méthodes de traitement en fonction de ses propres caractéristiques. 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 sapi, telles que l'implémentation d'applications Web via un serveur Web, leur exécution en mode script sur la ligne de commande, etc.
Si PHP est une voiture, alors le châssis de la voiture est PHP lui-même, Zend est le moteur (moteur) de la voiture et les différents composants sous Ext sont les roues de la voiture. comme une route, et la voiture peut rouler sur différents types de routes, et l'exécution d'un programme PHP fait que la voiture roule sur la route. Il nous faut donc : un moteur performant + les bonnes roues + la bonne chenille.
3. Sapi
Comme mentionné ci-dessus, Sapi permet aux applications externes d'échanger des données avec PHP via une série d'interfaces et peut implémenter des fonctions spécifiques en fonction des caractéristiques de différents applications. Certaines de nos méthodes de traitement sapi courantes sont :
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. 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 ces dernières années, fastcgi+PHP a été de plus en plus utilisé, et c'est également la seule méthode prise en charge par le serveur Web asynchrone. cli : Mode application pour les appels en ligne de commande
4. Processus d'exécution PHP et opcode
Jetons d'abord un coup d'œil au processus d'exécution du code PHP.
Comme vous pouvez le voir sur l'image, PHP implémente un processus d'exécution dynamique typique d'un langage : après avoir obtenu un morceau de code, après avoir traversé des étapes telles que l'analyse lexicale et l'analyse syntaxique, la source Le programme sera traduit en instructions (opcodes), puis la machine virtuelle ZEND exécute 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 toutes 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 des opcodes.
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 de traitement courantes :
PHP
ZEND_ASSIGN_SPEC_CV_CV_HANDLER
: Allocation de variables ($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
: Addition $a+2
ZEND_IS_EQUAL_SPEC_CV_CONST
: Jugement d'égalité $a==1
ZEND_IS_IDENTICAL_SPEC_CV_CONST
: Jugement d'égalité $a===1
5 HashTable — structure de données de base
HashTable. est la structure de données de base de zend.Il est utilisé pour implémenter presque toutes les fonctions courantes de PHP.Le tableau PHP que nous connaissons est également son application typique dans zend, comme les tables de symboles de fonctions, les variables globales, etc. sur la table de hachage à réaliser.
La table de hachage de PHP a les caractéristiques suivantes :
1. Prend en charge les requêtes clé>valeur typiques
2. Peut être utilisée 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 : il existe à la fois des tableaux associatifs et des tableaux d'index
5. " ,2332)
6. Prend en charge le parcours linéaire : comme foreach
La table de hachage Zend implémente une structure de hachage de table de hachage typique, et fournit en même temps une marche avant et arrière en attachant un double lien list Fonction pour parcourir un tableau. Sa structure est la suivante :
On peut voir qu'il existe à la fois une structure de hachage clé->valeur et un mode liste doublement chaînée dans la table de hachage, donc qu'il peut très facilement 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 utilise une liste chaînée pour résoudre les conflits. 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 chaînée bidirectionnelle 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.) :
PHP
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;
Tableau d'index PHP :
Le tableau d'index est notre tableau commun, accessible via des indices. Par exemple, $arr[0], Zend HashTable est normalisé en interne, et la valeur de hachage et nKeyLength (0) sont également affectées à la clé de type d'index. 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 les clés de type double, Zend HashTable les traitera comme des clés d'index
6. > PHP est un langage faiblement typé et ne distingue pas strictement les types de variables. PHP n'a pas besoin de spécifier le type lors de la déclaration des variables. PHP peut effectuer des conversions implicites de types de variables lors de l'exécution du programme. Comme d'autres langages fortement typés, une conversion de type explicite peut également être effectuée dans le programme. Les variables PHP peuvent être divisées en types simples (int, string, bool), types de collection (objet ressource tableau) et constantes (const). Toutes les variables ci-dessus ont la même structure zval sous le capot. Zval est une autre structure de données très importante dans zend, utilisée pour identifier et implémenter les variables PHP. Sa structure de données est la suivante : Zval est principalement composé. Composition de trois parties : type : spécifie le type de la variable (entier, chaîne, tableau, etc.) refcount&is_ref : utilisé pour implémenter le comptage de références (introduction détaillée plus tard) value : La partie centrale, qui stocke les données réelles de la variable Zvalue est utilisée pour enregistrer les données réelles d'une variable. Étant donné que plusieurs types doivent être stockés, zvalue est une union, implémentant ainsi un typage faible. La relation correspondante entre les types de variables PHP et leur stockage réel est la suivante : 1, 2, 3 , 4, 5, Le comptage de références est largement utilisé dans le recyclage de la mémoire, les opérations sur les chaînes, etc. Les variables en PHP sont une application typique du comptage de références. 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, zend pointe la variable vers les mêmes zval et ref_count++, et pendant l'opération de non-définition, le ref_count-1 correspondant. 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. Et si vous modifiez la valeur de l'une des variables ? 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, les exigences sont opposées aux types non-référence . Affectation de référence Les variables doivent être regroupées. La modification d'une variable modifie toutes les variables regroupées. Les nombres entiers et les nombres à 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. Pour les nombres à virgule flottante, similaires aux entiers, il ne fait pas de distinction entre float et double mais seulement double. En PHP, que dois-je faire si la plage entière est hors limites ? Dans ce cas, il sera automatiquement converti en type double. Vous devez faire attention à cela, car cela provoque de nombreuses astuces. 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 (incluse). En même temps, en PHP, trouver la longueur de la chaîne strlen est une opération O(1). Lors de l'ajout, de la modification ou de l'ajout d'opérations de chaîne, PHP réallouera de la mémoire pour générer de nouvelles chaînes. Enfin, pour des raisons de sécurité, PHP ajoutera toujours à la fin lors de la génération d'une chaîne. Méthodes courantes d'épissage de chaînes et comparaison de vitesse : Supposons qu'il existe les 4 variables suivantes : $strA= '. 123'; $strB = '456'; $intA=123; intB=456; Nous allons maintenant comparer et expliquer les méthodes d'épissage de chaînes suivantes : PHP $res = $strA.$strB et $res = « $strA$strB » Dans ce cas, zend mallocera à nouveau un morceau de mémoire et le traitera en conséquence, sa vitesse est généralement $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 $res = $intA .$intB C'est plus lent car une conversion de format implicite est requise dans la programmation réelle, vous devez également faire attention à éviter $strA = sprintf ( "%s%s",$strA. .$strB); Ce sera le moyen le plus lent, car sprintf n'est pas une structure de langage en PHP. 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. Les tableaux PHP sont naturellement implémentés via Zend HashTable. Comment implémenter l'opération foreach ? Foreach sur 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] sont équivalents Les variables de type ressource sont les variables les plus complexes en PHP et constituent é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. Obtenez 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 de ressources : les types de données de 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. 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. Pour plus de questions connexes, veuillez visiter le site Web PHP chinois : Tutoriel vidéo pratique PHPIS_LONG -> lvalue
IS_DOUBLE -> dvalue
IS_ARRAY -> ht
IS_STRING -> str
IS_RESOURCE -> lvalue
Pour zend, il n'y a pas de distinction entre les deux.
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!