PHP 運行模式
告知PHP是以一種什麼樣的方式執行,比如nginx是通過什麼和PHP進行交互,apache是通過什麼方式和PHP交互等等。
Php的運行模式有多種,從PHP源碼/sapi/目錄中我們可以看到php不同的運行模式。
運行模式詳解
Cli是php的命令行模式,可以把PHP看作類似shell的腳本語言,例如:
#!/path/php/bin/php -q
<?php
echo "hello,i am cli";
?>
或者
/path/php/bin/php index.php
<?php
echo "hello,i am cli";
?>
上述代碼是如何執行的?
為什麼能echo出hello,i am cli .
main函數開始
在 Sai/php_cli.c 中 的main 函數
第一步,獲取php 所在位置 一般都指path/php/bin/php,
sapi_module->executable_location = argv[0];
第二步,設置sapi 的cli模式
sapi_module_struct *sapi_module = &cli_sapi_module;
sapi_module_struct 的結構定義,在/main/SAPI.h裡定義
struct _sapi_module_struct {
char *name;
char *pretty_name;
...
}
我可以通過
<?Php
echo php_sapi_name();
?>
來獲取PHP的執行模式。
當然在sapi/php_cli.c 裡定義了
static sapi_module_struct cli_sapi_module = {
"cli", /* name */
"Command Line Interface", /* pretty name */
...
}
Do_cli 函數分析
第三步,執行 do_cli(argc, argv TSRMLS_CC);
比如執行 :
/path/php/bin/php -i ,相當於是 phpinfo();
/path/php/bin/php -v,獲取php的版本
/path/php/bin/php -h,獲取php命令詳解
第四步,在do_cli(argc, argv TSRMLS_CC) 中有這麼一段
if (script_file) {
...
}
/path/php/bin/php /index.php
那麼script_file 就是/index.php
if (script_file) {
...
if (cli_seek_file_begin(&file_handle, script_file, &lineno TSRMLS_CC) != SUCCESS) {
goto err;
}
...
}
通過 cli_seek_file_begin 檢查文件是否存在,例如我們隨便執行
/path/php/bin/php /xxx.php
如果/xxx.php文件不存在的話。就會報 Could not open input file: /xxx.php
VCWD_FOPEN 函數分析
在上述中已經提到通過 cli_seek_file_begin 去檢測PHP文件 是否存在。Php內核中定義了通過只讀的方式VCWD_FOPEN函數來
判斷文件是否存在,
在/TSRM/tsrm_virtual_cwd.h頭文件中,宏定義如下:
#define VCWD_FOPEN(path, mode) fopen(path, mode)
VCWD_REALPATH 函數分析
如果通過2.1.1.3的VCWD_FOPEN函數判斷文件存在,就會執行VCWD_REALPATH來過濾script_file 的特殊字符,並且返回絕對路徑。
例如:
1、/path/php/bin/php index.php
會得到
/path/php/bin/php /path/index.php
/path/php/bin/php .//index.php
會得到
/path/php/bin/php /path/index.php
根據執行模式進行
switch (behavior) {
case PHP_MODE_STANDARD: //php的標准模式
if (strcmp(file_handle.filename, "-")) {
cli_register_file_handles(TSRMLS_C);
}
//判斷如果是php -a 這樣的交互模式
if (interactive && cli_shell_callbacks.cli_shell_run) {
exit_status = cli_shell_callbacks.cli_shell_run(TSRMLS_C);
} else {
php_execute_script(&file_handle TSRMLS_CC);
exit_status = EG(exit_status);
}
break;
......
php_execute_script
在文件main/php_main.h裡定義了
PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC);
zend_execute_scripts
在文件Zend/zend_compile.h裡定義
ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_count, ...);