Maison >développement back-end >Problème PHP >Compréhension approfondie des principes PHP et de l'interaction entre PHP et les serveurs WEB

Compréhension approfondie des principes PHP et de l'interaction entre PHP et les serveurs WEB

王林
王林original
2019-08-19 15:27:233125parcourir

Tout le monde sait que PHP doit s'exécuter sur un serveur WEB spécifique, tel que Nginx, Apache, etc., mais comment PHP démarre-t-il, comment s'exécute-t-il sur le serveur et comment les deux interagissent-ils ?

1. Le serveur WEB appelle l'interface PHP

En prenant le serveur Apache comme exemple, voyons comment le serveur démarre PHP et appelle les méthodes en PHP. Lorsque le serveur Apache démarre et exécute PHP, il est généralement intégré via le module mod_php7 (s'il s'agit de la version php5.*, il s'agit du module mod_php5, et le nom du suffixe du module dépend de la version de php). La structure de mod_php7 est la suivante (le chemin du code source est php/sapi/apache2handler/mod_php7.c) :

AP_MODULE_DECLARE_DATA module php7_module = {
    STANDARD20_MODULE_STUFF,/* 宏,包括版本,版本,模块索引,模块名,下个模块指针等信息 */
    create_php_config,      /* create per-directory config structure */
    merge_php_config,       /* merge per-directory config structures */
    NULL,                   /* create per-server config structure */
    NULL,                   /* merge per-server config structures */
    php_dir_cmds,           /* 模块定义的所有指令 */
    php_ap2_register_hook   /* register hooks */
};

Quand Apache a besoin d'appeler une méthode en PHP, il lui suffit de communiquer la requête à PHP via le module mod_php7 et la couche PHP renverront les données à Apache après traitement, tout le processus est terminé (veuillez ajouter : lorsque le serveur Apache démarre PHP, il existe en fait deux méthodes de chargement, l'une est un chargement statique et l'autre est un chargement dynamique . La méthode de chargement du module mod_php5 qui vient d'être évoquée peut être comprise comme un chargement statique, c'est-à-dire que vous devez redémarrer le serveur Apache pour y charger PHP ; le chargement dynamique ne nécessite pas de redémarrer le serveur. Il vous suffit de charger le module fixe PHP sur le serveur. serveur en envoyant des signaux pour atteindre l'objectif de démarrage de PHP. Cependant, avant le chargement dynamique, vous devez compiler le module chargé dans une bibliothèque de liens dynamiques, puis le configurer dans le fichier de configuration du serveur). La structure du modèle d'Apache en PHP a été donnée ci-dessus. La structure des modules correspondants dans le serveur Apache est donnée ci-dessous, comme suit (le code source est dans Apache, le même ci-dessous) :

struct module_struct {
    int version;
    int minor_version;
    int module_index;
    const char *name;
    void *dynamic_load_handle;
    struct module_struct *next;
    unsigned long magic;
    void (*rewrite_args) (process_rec *process);
    void *(*create_dir_config) (apr_pool_t *p, char *dir);
    void *(*merge_dir_config) (apr_pool_t *p, void *base_conf, void *new_conf);
    void *(*create_server_config) (apr_pool_t *p, server_rec *s);
    void *(*merge_server_config) (apr_pool_t *p, void *base_conf, void *new_conf);
    const command_rec *cmds;
    void (*register_hooks) (apr_pool_t *p);
}

Vous pouvez voir php7_module et module_struct Il y a encore de grandes différences, mais si vous voyez la façon dont la macro php7_module.STANDARD20_MODULE_STUFF est définie, vous penserez peut-être que les deux structures sont très similaires. En fait, cette macro définit les 8 premiers paramètres de module_struct, qui sont définis comme. suit :

#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \
    MODULE_MAGIC_NUMBER_MINOR, \
    -1, \
    __FILE__, \
    NULL, \
    NULL, \
    MODULE_MAGIC_COOKIE, \
    NULL /* rewrite args spot */

Ensuite, php7_module.php_dir_cmds définit tous les jeux d'instructions du module. La définition spécifique est la suivante (le chemin du code est php/sapi/apache2handler/apache_config.c) :

const command_rec php_dir_cmds[] =
{
    AP_INIT_TAKE2("php_value", php_apache_value_handler, NULL, OR_OPTIONS, "PHP Value Modifier"),
    AP_INIT_TAKE2("php_flag", php_apache_flag_handler, NULL, OR_OPTIONS, "PHP Flag Modifier"),
    AP_INIT_TAKE2("php_admin_value", php_apache_admin_value_handler, NULL, ACCESS_CONF|RSRC_CONF, "PHP Value Modifier (Admin)
    "),
    AP_INIT_TAKE2("php_admin_flag", php_apache_admin_flag_handler, NULL, ACCESS_CONF|RSRC_CONF, "PHP Flag Modifier (Admin)"),
    AP_INIT_TAKE1("PHPINIDir", php_apache_phpini_set, NULL, RSRC_CONF, "Directory containing the php.ini file"),
    {NULL}
};

En d'autres termes, la couche PHP uniquement. Les cinq instructions ci-dessus sont fournies à Apache. Le code source d'implémentation de chaque instruction est également dans le fichier apache_config.c. Enfin, il reste php7_module.php_ap2_register_hook. Sa définition est la suivante (le code. le chemin est php/sapi/apache2handler/mod_php7.c) :

void php_ap2_register_hook(apr_pool_t *p)
{
    ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE);
#ifdef ZEND_SIGNALS
    ap_hook_child_init(zend_signal_init, NULL, NULL, APR_HOOK_MIDDLE);
#endif
    ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE);
}

php7_module.php_ap2_register_hook La fonction contient 4 hooks et les fonctions de traitement correspondantes pre_config, pre_config, post_config et child_init sont des hooks de démarrage, qui sont appelés au démarrage du serveur. . Le hook du gestionnaire est un hook de requête, c'est-à-dire que les requêtes du serveur sont des appels, et grâce à ces hooks, PHP peut être démarré via le serveur Apache.

À ce stade, vous devez déjà savoir comment le serveur WEB démarre PHP et appelle les méthodes en PHP. Laissez-moi maintenant vous expliquer comment PHP appelle l'interface du serveur WEB.

2.PHP appelle l'interface du serveur WEB

Avant de parler de ce problème, nous devons comprendre ce qu'est SAPI. SAPI est en fait un accord commun observé entre la couche d'abstraction du serveur et la couche d'abstraction du serveur. Cela peut être facilement compris. Lorsque PHP a besoin d'appeler une méthode sur le serveur, comme vider le cache, la méthode d'implémentation pour vider le cache est implémentée. sur le serveur, et la couche PHP ne le sait pas du tout. Comment appeler cette méthode sur le serveur ? À ce stade, les deux parties doivent conclure un accord, puis le serveur fournit un ensemble d'interfaces convenues à PHP. Nous appelons ces accords communs avec la couche d'abstraction du serveur l'interface SAPI.

La question est, pour le serveur Apache, nous pouvons fournir un ensemble de SAPI, mais si un autre serveur ou autre "tiers" vient la prochaine fois, alors devons-nous également leur fournir un ensemble de SAPI ? Qu'en est-il d'un SAPI séparé ? Nos développeurs PHP intelligents ont dû y penser, c'est-à-dire fournir un ensemble commun d'interfaces SAPI pour tous les "tiers", mais vous pouvez vous demander si les nouveaux "tiers" ont besoin de l'interface, votre SAPI commun n'en a pas. Oui , que dois-je faire ? Je crois comprendre qu'il faut ajouter de nouvelles fonctions à l'interface SAPI générale de PHP. Ceci n'est que mon opinion personnelle. La structure générale de SAPI est la suivante (chemin du code source : php/main/SAPI.h) : 🎜>

struct _sapi_module_struct {
    char *name;         // 名字
    char *pretty_name;  // 更好理解的名字
    int (*startup)(struct _sapi_module_struct *sapi_module);    // 启动函数
    int (*shutdown)(struct _sapi_module_struct *sapi_module);   // 关闭函数
    int (*activate)(TSRMLS_D);           // 激活
    int (*deactivate)(TSRMLS_D);         // 停用
    void (*flush)(void *server_context); // flush
    char *(*read_cookies)(TSRMLS_D);     //read Cookies
    //...
};

Cette structure a de nombreuses variables, je ne les listerai donc pas une par une. Expliquons brièvement les variables à l'intérieur : la fonction de démarrage est appelée lorsque SAPI est initialisé, la fonction d'arrêt est utilisée pour libérer les données SAPI. structure et mémoire, etc., read_cookie Il est appelé lorsque SAPI est activé, puis attribue la valeur obtenue par cette fonction à SG(request_info).cookie_data. Alors pour le SAPI général fourni par PHP, comment le serveur Apache personnalise-t-il sa propre interface ? La structure spécifique est la suivante (le chemin du code source est php/sapi/apache2handler/sapi_apache2.c) :

static sapi_module_struct apache2_sapi_module = {
    "apache2handler",
    "Apache 2.0 Handler",

    php_apache2_startup,            /* startup */
    php_module_shutdown_wrapper,    /* shutdown */

    NULL,                           /* activate */
    NULL,                           /* deactivate */

    php_apache_sapi_ub_write,       /* unbuffered write */
    php_apache_sapi_flush,          /* flush */
    php_apache_sapi_get_stat,       /* get uid */
    php_apache_sapi_getenv,         /* getenv */

    php_error,                      /* error handler */

    php_apache_sapi_header_handler, /* header handler */
    php_apache_sapi_send_headers,   /* send headers handler */
    NULL,                           /* send header handler */

    php_apache_sapi_read_post,      /* read POST data */
    php_apache_sapi_read_cookies,   /* read Cookies */

    php_apache_sapi_register_variables,
    php_apache_sapi_log_message,        /* Log message */
    php_apache_sapi_get_request_time,   /* Request Time */
    NULL,                               /* Child Terminate */

    STANDARD_SAPI_MODULE_PROPERTIES
};

Dans le répertoire de code source ci-dessus php/sapi/apache2handler/, tout est placé sous le répertoire php/ sapi est appelé via SAPI." Third Party", la structure des répertoires est celle indiquée dans la figure ci-dessous. Le répertoire php/sapi/apache2handler contient l'interface pour interagir avec PHP sapi_apache2.c est le fichier d'interface SAPI convenu entre PHP et Apache. .

Compréhension approfondie des principes PHP et de linteraction entre PHP et les serveurs WEB

看到这里,大家应该基本清楚PHP层是怎样调用服务器层的接口,为了巩固上面的知识,下面举个栗子,即在Apache服务器环境下读取cookie:

SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);

 对于任意一个服务器在加载时,我们都会指定sapi_module,Apache的sapi_module是apache2_sapi_module,它的read_cookies方法的是php_apache_sapi_read_cookies函数,这样就实现PHP层调用Apache的接口,是不是很简单呢:)

更多相关问题可以访问PHP中文网相关教程:https://www.php.cn/course/list/29/type/2.html

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