7

[笔记] PHP源码-02

第二章笔记

PHP的生命周期

  1. PHPSAPI接口开始,不同的SAPI接口有着不同的工作,例如,CLI模式下则是会
    初始化命令行的相关环境变量,其他情况下也类似。

  2. PHPPHP_MINIT_FUNCTION进行模块初始化操作,在整个生命周期内进行一次,接下来
    则是PHP_RINIT_FUNCTION进行模块的激活操作。

#define PHP_MINIT_FUNCTION      ZEND_MODULE_STARTUP_D
#define PHP_MSHUTDOWN_FUNCTION  ZEND_MODULE_SHUTDOWN_D
#define PHP_RINIT_FUNCTION      ZEND_MODULE_ACTIVATE_D
#define PHP_RSHUTDOWN_FUNCTION  ZEND_MODULE_DEACTIVATE_D

然后执行PHP_RSHUTDOWN_FUNCTION, PHP_MSHUTDOWN_FUNCTION 来结束本次请求,通常结尾

时调用die()/exit()来结束。

  1. 当然在进行模块的初始化之前还要进行其他的操作。

    • 初始化全局变量
    • 初始化若干常量
    • 初始化Zend引擎和核心组件
    • 解析php.ini
    • 全局操作函数的初始化
    • 初始化静态构建的模块和共享模块(MINIT)
    • 禁用函数和类
    • php_request_startup 用来做请求初始化操作
    • 激活Zend引擎
    • 激活SAPI,初始化SG(sapi_headers)SG(request_info)
    • 环境初始化
  2. 多进程/多线程SAPI生命周期
    Apache采用的是多进程模式,Apache本身包含了mod_php模块,这个模块的作用是以动态链接库
    的形式来调用php的,也就是说,当启动的时候会预先fork出来多个子进程,每个进程有它自己的开始阶段。
    当修改了php.ini文件时,由于apache不会主动关闭或者进程不被关闭,所以不会生效。

    多线程的php

  3. Apache 中的模块的引用
    mod_php7 模块是Apache中使用php的一种常见方式,是通过共享库也就是动态链接库来调用的

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,           /* command apr_table_t */
    php_ap2_register_hook   /* register hooks */
};

上面的结构体是mod_php7模块作为apache模块的结构体。可以看出,php是作为一个apache钩子从mod_php启动。

当然,作为一个php的模块,apache也有它自己的 sapi_module_struct。如下:

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

当然这其中有属于apache专有的方法,例如read_cookie函数的调用过程如下:

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

词法/语法分析

  • LEX/YACC 作词法分析器

  • Zend引擎将语法树解析成opcode,作为机器码运行。

0x01: 也谈nodejs