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);
}
...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。