Maison  >  Article  >  développement back-end  >  Le mécanisme de fonctionnement et les principes de PHP (couche inférieure)

Le mécanisme de fonctionnement et les principes de PHP (couche inférieure)

不言
不言original
2018-04-08 10:21:291719parcourir

php semble très simple, mais il n'est pas facile d'approfondir le mécanisme de fonctionnement et les principes de php. En plus de pouvoir l'utiliser, nous devons également connaître ses principes de fonctionnement sous-jacents, afin de pouvoir l'utiliser. de manière flexible et comprenons le mécanisme de fonctionnement de PHP Amis intéressés, apprenons ensemble

En parlant du mécanisme de fonctionnement de PHP, je vais d'abord vous présenter les modules PHP. PHP a trois modules au total : le noyau, le moteur Zend et. couche d'extension ; le noyau PHP est utilisé pour traiter les requêtes, les flux de fichiers, la gestion des erreurs et d'autres opérations associées ; le moteur Zend (ZE) est utilisé pour convertir les fichiers source en langage machine, puis l'exécuter sur une machine virtuelle ; un ensemble de fonctions, de bibliothèques de classes et de flux que PHP utilise pour exécuter certaines opérations spécifiques. Par exemple, nous avons besoin de l'extension mysql pour nous connecter à la base de données MySQL ; lorsque ZE exécute le programme, il peut avoir besoin de se connecter à plusieurs extensions. À ce stade, ZE passe le contrôle à l'extension et le renvoie après avoir traité la tâche spécifique.

Enfin, ZE renvoie les résultats du programme en cours d'exécution au noyau PHP, qui transmet ensuite les résultats à la couche SAPI et enfin les envoie au navigateur.

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 ? Pour bien utiliser le langage dynamique, nous devons d'abord le comprendre. La gestion de la mémoire et les modèles de framework sont dignes de notre référence, nous pouvons obtenir des fonctions 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 mode 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), les bibliothèques standard, etc. sont toutes implémentées via des extensions. Utilisateurs également Vous pouvez implémenter votre propre extension selon vos besoins pour atteindre 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 d'extension typiques).

Sapi : Le nom complet de Sapi est Server Application Programming Interface, qui est l'interface de programmation d'applications serveur. Sapi permet à PHP d'interagir avec les données périphériques via une série de fonctions de hook. 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 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 aussi la seule méthode supportée par l'asynchrone. serveur Web.

cli : Mode d'application pour les appels en ligne de commande

4. Processus d'exécution PHP &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 de langage dynamique typique : après avoir obtenu un morceau de code, après une analyse lexicale, une analyse syntaxique et d'autres étapes, le source Le programme 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 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, c'est-à-dire l'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 de traitement courantes :

ZEND_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 : épissage de chaîne $ un .$b

ZEND_ADD_SPEC_CV_CONST_HANDLER : opération d'addition $a+2

ZEND_IS_EQUAL_SPEC_CV_CONST : juger égal $a==1

ZEND_IS_IDENTICAL_SPEC_CV_CONST : juger égal $a=== 1

5. HashTable - structure de données de base

HashTable est la structure de données de base de zend. Elle est utilisée pour implémenter presque toutes les fonctions courantes de PHP. est son application typique. De plus, dans Zend, la table des symboles de fonction, les variables globales, etc. sont également implémentées sur la base d'une table de hachage.

La table de hachage de PHP présente les caractéristiques suivantes :

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

Peut être utilisée comme un tableau

Ajouter et supprimer des nœuds sont une complexité O(1)

la clé prend en charge les types mixtes : le tableau d'index de combinaison de nombres associatif existe en même temps

La valeur prend en charge les types mixtes : tableau ("string", 2332)

Traversée linéaire prise en charge : par exemple, foreach

La table de hachage Zend implémente une structure de hachage de table de hachage typique 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 :

Comme vous pouvez le voir, il existe à la fois des structures de hachage sous forme de clé->valeur et un mode liste doublement chaînée dans la table de hachage, ce qui le rend très pratique pour 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 la table de hachage est pleine, 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. En théorie, 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.) :

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

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é de trois parties :

type : précise 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 :

IS_LONG -> lvalue
IS_DOUBLE -> >IS_STRING -> ; str
IS_RESOURCE -> lvalue

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 à 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 à celles non- types de 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. Comme le montre la structure zvalue, 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 :

$res = $strA.$ strB et $res = « $strA$strB »

Dans ce cas, zend réallouera un morceau de mémoire et le traitera en conséquence, et sa vitesse est généralement

$strA = $ strA.$strB

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) ;

Ceci. sera le moyen le plus lent, car sprintf n'est pas une structure de langage en PHP. Il faut beaucoup de temps pour reconnaître 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 convertit 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.

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 pendant une longue période, non seulement après que toutes les variables y faisant référence soient hors de portée, mais même après la fin d'une requête et la génération d'une nouvelle requête. Ces ressources sont appelées ressources persistantes car elles persistent tout au long du cycle de vie du SAPI, à moins qu'elles ne soient spécifiquement détruites. 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.

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

Recommandations associées :

Méthode vscode (Visual Studio Code) de configuration de l'environnement de développement PHP (testé)_Programming Development_Software Tutorial

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