PHPカーネル解析(1)

黄舟
リリース: 2016-12-19 11:01:46
オリジナル
1949 人が閲覧しました

ここで読むPHPのバージョンはPHP-7.1.0 RC3、コードを読むためのプラットフォームはLinuxです

まずPHPの入り口を探すことです。PHPにはapache、php-fpm、cliモードとたくさんのモードがあります。始めたい場合は、最も単純な cli モデルから始めることができます。

それでは、まずこのコマンドがどのように実行されるかを

php -r 'echo 12;'
ログイン後にコピー

調べる必要があります。

コマンドラインのphpプログラムを見ているので、まずメインの入り口を探す必要があります。したがって、このエントリは sapi/cli/php_cli.c にあります。


最初に一連の変数を定義します

01      int c;    
02    zend_file_handle file_handle;    
03    int behavior = PHP_MODE_STANDARD;    
04    char *reflection_what = NULL;    
05    volatile int request_started = 0;    
06    volatile int exit_status = 0;    
07    char *php_optarg = NULL, *orig_optarg = NULL;    
08    int php_optind = 1, orig_optind = 1;    
09    char *exec_direct=NULL, *exec_run=NULL, *exec_begin=NULL, *exec_end=NULL;    
10    char *arg_free=NULL, **arg_excp=&arg_free;    
11    char *script_file=NULL, *translated_path = NULL;    
12    int interactive=0;    
13    int lineno = 0;    
14    const char *param_error=NULL;    
15    int hide_argv = 0;
ログイン後にコピー

次にこれ

sapi_module_struct *sapi_module = &cli_sapi_module;

これはsapi_module_struct構造体であり、sapiで最も重要なデータ構造です。その定義は main/SAPI.h にあります。


以下はコメントを追加したコードです:

01    struct _sapi_module_struct {  // SAPI模块结构    
02        char *name; // 应用层名称,比如cli,cgi等    
03        char *pretty_name; // 应用层更易读的名字,比如cli对应的就是Command Line Interface    
04    
05        int (*startup)(struct _sapi_module_struct *sapi_module); // 当一个应用要调用php的时候,这个模块启动的时候会调用的函数    
06        int (*shutdown)(struct _sapi_module_struct *sapi_module); // 当一个应用要调用php的时候,这个模块结束的时候会调用的函数    
07    
08        int (*activate)(void); // 在处理每个request的时候,激活需要调用的函数    
09        int (*deactivate)(void); // 在处理完每个request的时候,收尾时候要调用的函数    
10    
11        size_t (*ub_write)(const char *str, size_t str_length); // 这个函数告诉php如何输出数据    
12        void (*flush)(void *server_context); // 提供给php的刷新缓存的函数指针    
13        zend_stat_t *(*get_stat)(void); // 用来判断要执行文件的权限,来判断是否有执行权限    
14        char *(*getenv)(char *name, size_t name_len); // 获取环境变量的方法    
15    
16        void (*sapi_error)(int type, const char *error_msg, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); // 错误处理方法    
17    
18        int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers); // 这个函数会在我们调用header()的时候被调用    
19        int (*send_headers)(sapi_headers_struct *sapi_headers); // 发送所有的header    
20        void (*send_header)(sapi_header_struct *sapi_header, void *server_context); // 单独发送某一个header    
21    
22        size_t (*read_post)(char *buffer, size_t count_bytes); // 如何获取HTTP POST中的数据    
23        char *(*read_cookies)(void);  // 如何获取cookie中的数据    
24    
25        void (*register_server_variables)(zval *track_vars_array); // 这个函数可以给$_SERVER中获取变量    
26        void (*log_message)(char *message, int syslog_type_int); // 输出错误信息函数    
27        double (*get_request_time)(void); // 获取请求时间的函数    
28        void (*terminate_process)(void);  // TODO: 调用exit的时候调用的方法    
29    
30        char *php_ini_path_override;  // PHP的ini文件被复写了所复写的地址    
31    
32        void (*default_post_reader)(void); // 这里和前面的read_post有个差别,read_post负责如何获取POST数据,而这里的函数负责如何解析POST数据    
33        void (*treat_data)(int arg, char *str, zval *destArray); // 对数据进行处理,比如进行安全过滤等。 default_post_reader/tread_data/input_filter是三个能对输入进行过滤和处理的函数    
34        char *executable_location; // 执行的地理位置    
35    
36        int php_ini_ignore; // 是否不使用任何ini配置文件,比如php -n 就将这个位置设置为1    
37        int php_ini_ignore_cwd; // 不在当前路径寻找php.ini    
38    
39        int (*get_fd)(int *fd); // 获取执行文件的fd    
40    
41        int (*force_http_10)(void); // 强制使用http1.0    
42    
43        int (*get_target_uid)(uid_t *); // 获取执行程序的uid    
44        int (*get_target_gid)(gid_t *); // 获取执行程序的gid    
45    
46        unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len); // 对输入进行过滤。比如将输入参数填充到自动全局变量$_GET, $_POST, $_COOKIE中    
47    
48        void (*ini_defaults)(HashTable *configuration_hash); // 默认的ini配置    
49        int phpinfo_as_text; // 是否打印phpinfo信息    
50    
51        char *ini_entries; // 有没有附带的ini配置,比如使用php -d date.timezone=America/Adak,可以在命令行中设置时区    
52        const zend_function_entry *additional_functions; // 每个SAPI模块特有的一些函数注册,比如cli的cli_get_process_title    
53        unsigned int (*input_filter_init)(void); // TODO:    
54    };
ログイン後にコピー

要約すべき点がいくつかあります:


cliモードはヘッダーを送信する必要がないため、ヘッダー処理に対応する関数が3つあります

1    sapi_cli_header_handler    
2    sapi_cli_send_headers    
3    sapi_cli_send_header
ログイン後にコピー

実際、それらはすべて空の実装です。


Cookieについても同様です

sapi_cli_read_cookies
ログイン後にコピー

他の定義された関数が見つかったら、それを分析します。

main

main 関数に戻ります。 上記の構造に基づいて、

1    argv = save_ps_args(argc, argv); //这里获取一次当前执行进程的参数,环境变量等。为的是对特定平台,修正下argv变量以供后续使用。    
2    
3    cli_sapi_module.additional_functions = additional_functions; // cli模式特有的函数
ログイン後にコピー

signal

1    #ifdef HAVE_SIGNAL_H    
2    #if defined(SIGPIPE) && defined(SIG_IGN)    
3         // 忽略SIGPIPE是为了如果php是socket的客户端,那么当服务端关闭的话,会返回一个PIPE的信号,为的是当前的程序不会因为这个而结束    
4        signal(SIGPIPE, SIG_IGN);    
5    #endif    
6    #endif
ログイン後にコピー

が理解されます。 以上が PHP カーネル解析 (1) の内容です。 PHP 中国語 Web サイト (www.php.cn)!


関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のおすすめ
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!