php内核分析(四)-do_cli

这里阅读的php版本为PHP-7.1.0 RC3,阅读代码的平台为linux

# main

把剩下的代码增加了下注释全部贴出来了(这个是简化后的main函数,去掉了一些无关紧要的代码段):

01 int main(int argc, char *argv[])
02 {
03     ...
04     sapi_module_struct *sapi_module = &cli_sapi_module;
05  
06     argv = save_ps_args(argc, argv); //这里获取一次当前执行进程的参数,环境变量等。为的是对特定平台,修正下argv变量以供后续使用。
07  
08     cli_sapi_module.additional_functions = additional_functions; // cli模式特有的函数
09  
10      ...
11  
12  
13 #ifdef ZTS
14     tsrm_startup(1, 1, 0, NULL);
15     (void)ts_resource(0);
16     ZEND_TSRMLS_CACHE_UPDATE();
17 #endif
18  
19     zend_signal_startup();  // 设置信号,把一些需要反应的信号位设置为0
20  
21     // 获取参数,做一些对应的初始化行为,或者一些简单的操作,比如help
22     while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2))!=-1) {
23         switch (c) { // 这里的c是代表返回的字符串的ascii码值
24             case 'c':
25                 ...
26             case 'n':
27                 ini_ignore = 1; // 不使用ini文件,通过代码或者其他指定ini值
28                 break;
29             case 'd': { // 配置ini的key,val值在命令行中,下面的行为都是修改ini_entries这个变量
30                 ...
31             }
32             case 'h'/* help & quit */
33             case '?':
34                 php_cli_usage(argv[0]);
35                 goto out;
36             case 'i'case 'v'case 'm':
37                 sapi_module = &cli_sapi_module;
38                 goto exit_loop;
39             case 'e'/* enable extended info output */
40                 use_extended_info = 1;
41                 break;
42         }
43     }
44 exit_loop:
45  
46     sapi_module->ini_defaults = sapi_cli_ini_defaults; // 设置初始化的ini值
47     sapi_module->php_ini_path_override = ini_path_override; //设置重写后的ini_path地址,如果是php -c的话,这个就为非null
48     sapi_module->phpinfo_as_text = 1; // 打开打印phpinfo的开关,需要的时候可以把phpinfo打印出来
49     sapi_module->php_ini_ignore_cwd = 1; // 不在当前路径寻找php.ini
50     sapi_startup(sapi_module); // sapi初始化行为,比如初始化全局变量SG
51     sapi_started = 1; // 标记,表示已经调用了startup,关闭的时候需要调用shundown
52     ...
53  
54     // 开始调用sapi的startup方法,对cli模式,实际上是调用php_cli_startup方法
55     if (sapi_module->startup(sapi_module) == FAILURE) {
56         exit_status = 1;
57         goto out;
58     }
59     module_started = 1; // 标记位,标记已经调用了module的startup方法
60  
61     ...
62  
63     zend_first_try {
64             exit_status = do_cli(argc, argv);  // 这个是实际上调用的内容
65     } zend_end_try();
66 out:  // 这个代码段已经是要退出了
67     if (ini_path_override) {
68         free(ini_path_override);
69     }
70     if (ini_entries) {
71         free(ini_entries);
72     }
73     if (module_started) {
74         php_module_shutdown();
75     }
76     if (sapi_started) {
77         sapi_shutdown();
78     }
79 #ifdef ZTS
80     tsrm_shutdown();
81 #endif
82  
83     cleanup_ps_args(argv);
84     exit(exit_status);
85 }

其实看伪码很简单:

1 tsrm_startup(1, 1, 0, NULL);  // TSM启动
2 zend_signal_startup();  // 信号设置
3 sapi_startup(sapi_module);  // SAPI启动
4 sapi_module->startup(sapi_module); // 当前模块的startup
5 do_cli(argc, argv); // 做实际的行为
6 php_module_shutdown();  // 当前模块的shutdown
7 sapi_shutdown(); // SAPI关闭
8 tsrm_shutdown(); // TSM关闭

好了,其实看了一圈,里面最重的函数是do_cli了。

php参数

do_cli里面你会看到根据参数的不同,有很多分支,这里你就需要了解这些参数都是什么用的。

参数
作用
实例

do_cli

我们把do_cli函数的整个函数去掉多余代码,仅保留关键代码如下:

001 static int do_cli(int argc, char **argv)
002 {
003     ...
004  
005     zend_try {
006  
007         // 这里处理了 i-输出phpinfo内容/ v-输出php版本 / m-输出扩展信息
008         while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
009             switch (c) {
010  
011             case 'i'// 输出phpinfo内容
012                 ...
013                 php_print_info(0xFFFFFFFF);
014                 ...
015                 goto out;
016  
017             case 'v'// 输出php版本信息
018                 ...
019                     get_zend_version()
020                 ...
021                 goto out;
022  
023             case 'm'// 列出所有模块
024                 ...
025                 print_extensions();
026                 ...
027                 goto out;
028  
029             default:
030                 break;
031             }
032         }
033  
034         ...
035  
036         // 下面的代码做了几个事情:
037         // 1 根据参数设置了behavior参数
038         // 2 有执行文件的就将文件存在script_file
039         while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
040             switch (c) {
041  
042             case 'a'// php的交互模式
043                 ...
044                 interactive=1;
045                 ...
046                 break;
047  
048             case 'C'// 不要把cwd目录变成脚本所在的目录。这个默认就是cwd是当前执行路径,所以这里什么都不做。
049                 break;
050  
051             case 'F'// php -F <file> 进入交互模式,每执行一行就执行一次<file>文件
052                 ...
053                 behavior=PHP_MODE_PROCESS_STDIN;
054                 script_file = php_optarg;
055                 break;
056  
057             case 'f'// php -f <file> 解析并执行文件
058                 ...
059                 script_file = php_optarg;
060                 break;
061  
062             case 'l':  // 检查文件的语法是否有错误
063                 ...
064                 behavior=PHP_MODE_LINT;
065                 break;
066  
067             case 'q'// 安静模式,默认也是安静模式
068                 break;
069  
070             case 'r'// 从命令行直接执行脚本
071                 ...
072                 behavior=PHP_MODE_CLI_DIRECT;
073                 exec_direct=php_optarg;
074                 break;
075  
076             case 'R'// 每行输入的时候执行一次code脚本,比如 php -R 'echo 12;'
077                 ...
078                 behavior=PHP_MODE_PROCESS_STDIN;
079                 exec_run=php_optarg;
080                 break;
081  
082             case 'B'// 在每次输入开始之前执行一次code脚本
083                 ...
084                 behavior=PHP_MODE_PROCESS_STDIN;
085                 exec_begin=php_optarg;
086                 break;
087  
088             case 'E'// 在每次输入结束之后执行一次code脚本, 上面的 RBE可以参考一个例子:find conf.d | php -B '$l=0;' -R '$l += count(@file($argn));' -E 'echo "Total Lines: $l\n";'
089                 ...
090                 behavior=PHP_MODE_PROCESS_STDIN;
091                 exec_end=php_optarg;
092                 break;
093  
094             case 's'// 使用html高亮方式显示代码,这个或许在一些代码显示的时候需要用到
095                 ...
096                 behavior=PHP_MODE_HIGHLIGHT;
097                 break;
098  
099             case 'w':  // php <file> -w 能把<file>中的评论和多余的空格去掉
100                 ...
101                 behavior=PHP_MODE_STRIP;
102                 break;
103  
104             case 'z'// 加载外部扩展
105                 zend_load_extension(php_optarg);
106                 break;
107             case 'H'// 隐藏所有参数
108                 hide_argv = 1;
109                 break;
110             case 10: // 显示function定义
111                 behavior=PHP_MODE_REFLECTION_FUNCTION;
112                 reflection_what = php_optarg;
113                 break;
114             case 11: // 显示class定义
115                 behavior=PHP_MODE_REFLECTION_CLASS;
116                 reflection_what = php_optarg;
117                 break;
118             case 12: // 显示扩展定义,注意这里是php扩展
119                 behavior=PHP_MODE_REFLECTION_EXTENSION;
120                 reflection_what = php_optarg;
121                 break;
122             case 13: // 显示zend扩展定义, 比如xdebug
123                 behavior=PHP_MODE_REFLECTION_ZEND_EXTENSION;
124                 reflection_what = php_optarg;
125                 break;
126             case 14: // 显示扩展的对应配置
127                 behavior=PHP_MODE_REFLECTION_EXT_INFO;
128                 reflection_what = php_optarg;
129                 break;
130             case 15: // 显示ini配置
131                 behavior = PHP_MODE_SHOW_INI_CONFIG;
132                 break;
133             default:
134                 break;
135             }
136         }
137  
138         ...
139  
140         // 初始化request之后,执行了request_startup
141         if (php_request_startup()==FAILURE) {
142             ...
143             goto err;
144         }
145         ...
146  
147         zend_is_auto_global_str(ZEND_STRL("_SERVER"));
148  
149         // 根据不同的行为做不同的具体操作,这个是核心方法
150         switch (behavior) {
151         case PHP_MODE_STANDARD:  // 标准,就是执行一个脚本文件
152             ...
153                 php_execute_script(&file_handle);
154             ...
155             break;
156         case PHP_MODE_LINT: // 只检查文件有没有语法错误
157             exit_status = php_lint_script(&file_handle);
158             ...
159             break;
160         case PHP_MODE_STRIP:
161             ...
162                 zend_strip();
163             ...
164             break;
165         case PHP_MODE_HIGHLIGHT:
166             ...
167             php_get_highlight_struct(&syntax_highlighter_ini);
168             zend_highlight(&syntax_highlighter_ini);
169             goto out;
170             break;
171         case PHP_MODE_CLI_DIRECT:
172             ...
173             if (zend_eval_string_ex(exec_direct, NULL, "Command line code", 1) == FAILURE) {
174                 exit_status=254;
175             }
176             break;
177  
178         case PHP_MODE_PROCESS_STDIN:
179                 ...
180                 zend_eval_string_ex(exec_end, NULL, "Command line end code", 1)
181                 ...
182                 break;
183         case PHP_MODE_REFLECTION_FUNCTION:
184         case PHP_MODE_REFLECTION_CLASS:
185         case PHP_MODE_REFLECTION_EXTENSION:
186         case PHP_MODE_REFLECTION_ZEND_EXTENSION:
187             ...
188             ZVAL_STRING(&arg, reflection_what);
189             object_init_ex(&ref, pce);
190             ...
191             zend_call_method_with_1_params(&ref, pce, &pce->constructor, "__construct", NULL, &arg);
192             ...
193             break;
194         case PHP_MODE_REFLECTION_EXT_INFO:
195             ...
196             if ((module = zend_hash_str_find_ptr(&module_registry, lcname, len)) == NULL) {
197                 ...
198                     display_ini_entries(NULL);
199                 ...
200             }
201             ...
202             break;
203         case PHP_MODE_SHOW_INI_CONFIG:
204             ...
205             break;
206         }
207     } zend_end_try();
208  
209 out:
210     ...
211 err:
212     ...
213 }</file></file></file></file></file>

整个200行的代码就很好理解了,整个是包在一个zend_try...zend_catch中的。做了几步:

  • 处理-i, -m, -v参数
  • 对其他的参数设置behavior,script_file等变量
  • 根据behavior做不同的行为

回到我们的初步计划,我们想要了解的事:

我们的根据-r的参数配置寻找。

它实际上时调用了

1 zend_eval_string_ex(exec_direct, NULL, "Command line code", 1)

这里的exec_direct是 echo 12字符串

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值