configure & make 默認構建目標爲 php-cli,相關代碼在 sapi/cli 目錄下,php_cli.c 文件中可以找到 main(入口)函數,大概流程以下:php
命令行參數處理編程
cli_sapi_module 初始化segmentfault
sapi_module->startupapi
do_cli or do_cli_serverapp
清理工做函數
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 是一個靜態全局變量,定義在 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 函數定義在 php_cli.c 文件中,大體流程以下:指針
根據命令行選項 肯定 behavior(解釋器行爲)rest
根據 behavior 執行相應的動做
經過執行 sapi/cli/php --help 能夠查看全部的 php-cli 命令行選項,咱們經過幾個簡單的選項來分析解釋器執行流程
該模式下,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 源代碼學習: 語法分析,這裏作個簡要介紹
經過搜索源代碼能夠發現 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; }