php cli

php cli是sapi的具体实现之一,他是在具体终端上现实的。另外包括cgi,fpm,embed,也都是sapi的具体实现。这里sapi可以理解为php的一个外部环境展示的接口。每种具体模式的实现都会有选择的去实现他声明的一些方法。而cli是相对简单的实现逻辑。cli main程序入口在 \sapi\cli\php_cli.c中。另外还有一个内置的web服务器,在sapi\cli\php_cli_server.c中,他有独立的cli_server_sapi_module结构体赋值实现,同样调用php_module_startup,可以与cli脚本执行做对比着看。

sapi_module_struct 总览

cli流程

操作OS环境判断->初始化变量->加载cli环境下特殊的函数(eg:cli_set_process_title)->线程安全 TSRM* ->信号【(非)可靠信号】屏蔽处理zend_signal_startup->命令行参数解析->启动sapi_module->startup(cli_sapi_module)->具体执行do_cli()

一些命令行解析及初始化

...
sapi_module->ini_defaults = sapi_cli_ini_defaults;//初始化INI默认设置
sapi_module->php_ini_path_override = ini_path_override;//cli 下php.ini路径,设置重写后的ini_path地址,php -c <path>|<file>可以指定具路径
sapi_module->phpinfo_as_text = 1;
sapi_module->php_ini_ignore_cwd = 1;//默认不在当前路径寻找php.ini
sapi_startup(sapi_module);//sapi启动init
sapi_started = 1;//标记已经开始
sapi_module->php_ini_ignore = ini_ignore;
 //通过startup启动了!
if (sapi_module->startup(sapi_module) == FAILURE) {
...

cli_sapi_module

    sapi_module_struct *sapi_module = &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 */

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

    sapi_cli_ub_write,                /* unbuffered write */
    sapi_cli_flush,                    /* flush */
    NULL,                            /* get uid */
    NULL,                            /* getenv */

    php_error,                        /* error handler */

    sapi_cli_header_handler,        /* header handler */
    sapi_cli_send_headers,            /* send headers handler */
    sapi_cli_send_header,            /* send header handler */

    NULL,                            /* read POST data */
    sapi_cli_read_cookies,          /* read Cookies */

    sapi_cli_register_variables,    /* register server variables 像$_SERVER中注册变量*/
    sapi_cli_log_message,            /* Log message */
    NULL,                            /* Get request time */
    NULL,                            /* Child terminate */

    STANDARD_SAPI_MODULE_PROPERTIES
};

核心do_cli的执行

# 开始涉及zend_file_handle结构体
typedef struct _zend_file_handle {
    union {
        int           fd; //文件描述符
        FILE          *fp;//文件句柄
        zend_stream   stream;//zend自己的stream
    } handle;
    const char        *filename;//文件名
    zend_string       *opened_path;//已打开路径
    zend_stream_type  type;// type是具体类型,是个枚举。包括以下
    ZEND_HANDLE_FILENAME,
    ZEND_HANDLE_FD,
    ZEND_HANDLE_FP,
    ZEND_HANDLE_STREAM,
    ZEND_HANDLE_MAPPED
    zend_bool free_filename;//销毁时是否释放 filename
} zend_file_handle;

    /*接下来是一些针对php cli下一些特殊的命令行参数的处理,
    比如-r -i -v -m;-a -c -f等等
    ,而这些参数的传递导致了behavior
    的switch case(默认为PHP_MODE_STANDARD)*/
switch (behavior) {
        case PHP_MODE_STANDARD://默认PHP文件执行到这里
            if (strcmp(file_handle.filename, "Standard input code")) {
                cli_register_file_handles();// 标准in,out,error
            }

            if (interactive && cli_shell_callbacks.cli_shell_run) {
                exit_status = cli_shell_callbacks.cli_shell_run();
            } else {
                php_execute_script(&file_handle);//传入PHP文件 开始执行PHP 并返回执行状态
                exit_status = EG(exit_status);
            }
            break;
        case PHP_MODE_LINT: //检查语法错误
            exit_status = php_lint_script(&file_handle);
            if (exit_status==SUCCESS) {
                zend_printf("No syntax errors detected in %s\n", file_handle.filename);
            } else {
                zend_printf("Errors parsing %s\n", file_handle.filename);
            }
            break;
... 

请求结束

...
if (request_started) {//结束请求
        php_request_shutdown((void *) 0);
    }
...

最靓的仔是他↓

image.png


牙小木木
1.5k 声望80 粉丝

iamtb.cn