PHP-7.1 源代碼學習:php-cli 啓動流程

前言

php cli main 函數

configure & make 默認構建目標爲 php-cli,相關代碼在 sapi/cli 目錄下,php_cli.c 文件中可以找到 main(入口)函數,大概流程以下:php

  • 命令行參數處理編程

  • cli_sapi_module 初始化segmentfault

  • sapi_module->startupapi

  • do_cli or do_cli_serverapp

  • 清理工做函數

sapi_module_struct

C 語言系統編程經常使用手法,經過 struct 中聲明 函數指針 類型的字段來實現相似面向對象中抽象類的概念,在 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);
    ...
    char *ini_entries;
    const zend_function_entry *additional_functions;
    unsigned int (*input_filter_init)(void);
}

cli_sapi_module

cli_sapi_module 是一個靜態全局變量,定義在 php_cli.c 中,你能夠將它理解成是 sapi_module_struct "類" 的一個 "實例",結構體中 "掛載" 了 cli 特定的實現函數:命令行

/* {{{ sapi_module_struct cli_sapi_module
 */
static sapi_module_struct cli_sapi_module = {
    "cli",                            /* name */
    "Command Line Interface",        /* pretty name */

    ...
    php_cli_startup,                /* startup */
    php_module_shutdown_wrapper,    /* shutdown */
    ...

    STANDARD_SAPI_MODULE_PROPERTIES
};

do_cli

do_cli 函數定義在 php_cli.c 文件中,大體流程以下:指針

  • 根據命令行選項 肯定 behavior(解釋器行爲)rest

  • 根據 behavior 執行相應的動做

經過執行 sapi/cli/php --help 能夠查看全部的 php-cli 命令行選項,咱們經過幾個簡單的選項來分析解釋器執行流程

PHP_MODE_CLI_DIRECT

該模式下,php-cli 會執行解釋執行經過命令行參數傳遞的 code

case PHP_MODE_CLI_DIRECT:
    cli_register_file_handles();
    if (zend_eval_string_ex(exec_direct, NULL,   
        "Command line code", 1) == FAILURE) {
                exit_status=254;
    }
    break;

追蹤 zend_eval_string_ex 的函數調用,定位到 zend_execute_API.c 文件中 zend_eval_stringl 函數,代碼邏輯已經很清楚了:先調用 zend_compile_string 函數編譯代碼生成字節碼 new_op_array,再調用 zend_execute 函數執行生成的字節碼

ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr,   
char *string_name) {
    ...
    original_compiler_options = CG(compiler_options);
    CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
    new_op_array = zend_compile_string(&pv, string_name);
    CG(compiler_options) = original_compiler_options;

    if (new_op_array) {
        zend_try {
            ZVAL_UNDEF(&local_retval);
            zend_execute(new_op_array, &local_retval);
        } zend_catch {
            destroy_op_array(new_op_array);
            efree_size(new_op_array, sizeof(zend_op_array));
            zend_bailout();
        } zend_end_try();
        ...
    } else {
        retval = FAILURE;
    }
    zval_dtor(&pv);
    return retval;
}

zend_compile_string 屬於語法分析內容,參考 PHP-7.1 源代碼學習: 語法分析,這裏作個簡要介紹

compile_string

經過搜索源代碼能夠發現 zend_compile_string 最終調用 compile_string

zend_op_array *compile_string(zval *source_string, char *filename)
{
    zend_lex_state original_lex_state;
    zend_op_array *op_array = NULL;
    zval tmp;

    if (Z_STRLEN_P(source_string)==0) {
        return NULL;
    }

    ZVAL_DUP(&tmp, source_string);
    convert_to_string(&tmp);
    source_string = &tmp;

    zend_save_lexical_state(&original_lex_state);
    if (zend_prepare_string_for_scanning(source_string, filename) == SUCCESS) {
        BEGIN(ST_IN_SCRIPTING);
        op_array = zend_compile(ZEND_EVAL_CODE);
    }

    zend_restore_lexical_state(&original_lex_state);
    zval_dtor(&tmp);

    return op_array;
}

總結

相關文章
相關標籤/搜索