PHP8 の基礎となるカーネル ソース コードである SAPI の詳細な分析 (1)
この記事では、PHP8 の基礎となるカーネル ソース コードを詳細に分析し、SAPI について学びます。一定の参考値があるので、困っている友達が参考になれば幸いです。
# おすすめ関連記事: 「in 以下の環境は docker の下に構築されていますPHP8 の基礎となるカーネル ソース コードの分析 - 配列 (1)」
[root@a951700e857d cui-php]# php -v PHP 8.0.2 (cli) (built: Mar 2 2021 02:40:03) ( NTS ) Copyright (c) The PHP Group Zend Engine v4.0.2, Copyright (c) Zend Technologies [root@a951700e857d cui-php]#
Zend SAPI の深い理解 (Zend SAPI Internals)https://link.zhihu.com/?target=https://www.laruence.com/2008/08/12/180.html
#SAPI (Server Application Programimg Interface、サーバー アプリケーション プログラミング インターフェイス) は、PHP の外部環境のプロキシに相当します。 PHPは端末上で適用することもできますが、端末上で適用するSAPIをCLI SAPI、Webサーバー上で適用するSAPIをCGI SAPIと呼びます。
これは、前後を接続する中間層または接着剤に相当します。
sapi のコア定義とマクロ ファイルは、sapi.h
# にあります。
## cgi_main.c
//* sapi_module_struct cgi_sapi_module static sapi_module_struct cgi_sapi_module = { "cgi-fcgi", /* name */ "CGI/FastCGI", /* pretty name */ php_cgi_startup, /* startup */ php_module_shutdown_wrapper, /* shutdown */ sapi_cgi_activate, /* activate */ sapi_cgi_deactivate, /* deactivate */ sapi_cgi_ub_write, /* unbuffered write */ sapi_cgi_flush, /* flush */ NULL, /* get uid */ sapi_cgi_getenv, /* getenv */ php_error, /* error handler */ NULL, /* header handler */ sapi_cgi_send_headers, /* send headers handler */ NULL, /* send header handler */ sapi_cgi_read_post, /* read POST data */ sapi_cgi_read_cookies, /* read Cookies */ sapi_cgi_register_variables, /* register server variables */ sapi_cgi_log_message, /* Log message */ NULL, /* Get request time */ NULL, /* Child terminate */ STANDARD_SAPI_MODULE_PROPERTIES };
struct _sapi_module_struct { char *name; char *pretty_name; int (*startup)(struct _sapi_module_struct *sapi_module); int (*shutdown)(struct _sapi_module_struct *sapi_module); int (*activate)(void); int (*deactivate)(void); size_t (*ub_write)(const char *str, size_t str_length); void (*flush)(void *server_context); zend_stat_t *(*get_stat)(void); char *(*getenv)(const char *name, size_t name_len); void (*sapi_error)(int type, const char *error_msg, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers); int (*send_headers)(sapi_headers_struct *sapi_headers); void (*send_header)(sapi_header_struct *sapi_header, void *server_context); size_t (*read_post)(char *buffer, size_t count_bytes); char *(*read_cookies)(void); void (*register_server_variables)(zval *track_vars_array); void (*log_message)(const char *message, int syslog_type_int); double (*get_request_time)(void); void (*terminate_process)(void); char *php_ini_path_override; void (*default_post_reader)(void); void (*treat_data)(int arg, char *str, zval *destArray); char *executable_location; int php_ini_ignore; int php_ini_ignore_cwd; /* don't look for php.ini in the current directory */ int (*get_fd)(int *fd); int (*force_http_10)(void); int (*get_target_uid)(uid_t *); int (*get_target_gid)(gid_t *); unsigned int (*input_filter)(int arg, const char *var, char **val, size_t val_len, size_t *new_val_len); void (*ini_defaults)(HashTable *configuration_hash); int phpinfo_as_text; char *ini_entries; const zend_function_entry *additional_functions; unsigned int (*input_filter_init)(void); };
struct _sapi_module_struct { char *name; // 名字,如cli、 fpm-fcgi等 char *pretty_name; // 更易理解的名字,比如fpm-fcgi对应的为FPM/FastCGI int (*startup)(struct _sapi_module_struct *sapi_module); //模块启动时调用的函数 int (*shutdown)(struct _sapi_module_struct *sapi_module); //模块结束时调用的函数 int (*activate)(void); // 处理request时,激活需要调用的函数指针 int (*deactivate)(void); // 处理完request时,使要调用的函数指针无效 size_t (*ub_write)(const char *str, size_t str_length); // 这个函数指针用于输出数据 void (*flush)(void *server_context); // 刷新缓存的函数指针 zend_stat_t *(*get_stat)(void); // 判断对执行文件是否有执行权限 char *(*getenv)(char *name, size_t name_len); // 获取环境变量的函数指针 void (*sapi_error)(int type, const char *error_msg, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); // 错误处理函数指针 int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers); //调用header()时被调用的函数指针 int (*send_headers)(sapi_headers_struct *sapi_headers); // 发送全部header的函数指针 void (*send_header)(sapi_header_struct *sapi_header, void *server_context); // 发送某一个header的函数指针 size_t (*read_post)(char *buffer, size_t count_bytes); // 获取HTTP POST中数据的函数指针 char *(*read_cookies)(void); // 获取cookie中数据的函数指针 void (*register_server_variables)(zval *track_vars_array); // 从$_SERVER中获取变量的函数指针 void (*log_message)(char *message, int syslog_type_int); // 输出错误信息函数指针 double (*get_request_time)(void); // 获取请求时间的函数指针 void (*terminate_process)(void); // 调用exit退出时的函数指针 char *php_ini_path_override; // PHP的ini文件被复写的地址 void (*default_post_reader)(void); //负责解析POST数据的函数指针 void (*treat_data)(int arg, char *str, zval *destArray); // 对数据进行处理的函数指针 char *executable_location; // 执行的地理位置 int php_ini_ignore; // 是否不使用任何ini配置文件 int php_ini_ignore_cwd; // 忽略当前路径的php.ini int (*get_fd)(int *fd); // 获取执行文件的fd的函数指针 int (*force_http_10)(void); // 强制使用http 1.0版本的函数指针 int (*get_target_uid)(uid_t *); // 获取执行程序的uid的函数指针 int (*get_target_gid)(gid_t *); // 获取执行程序的gid的函数指针 unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len); // 对输入进行过滤的函数指针。比如将输入参数填充到自动全局变量$_GET、$_POST、$_COOKIE中 void (*ini_defaults)(HashTable *configuration_hash); // 默认的ini配置的函数指针,把ini配置信息存在HashTable中 int phpinfo_as_text; // 是否输出phpinfo信息 char *ini_entries; // 执行时附带的ini配置,可以使用php -d设置 const zend_function_entry *additional_functions; // 每个SAPI模块特有的一些函数注册,比如cli的cli_get_process_title unsigned int (*input_filter_init)(void); };
この構造は非常に重要です。CLI ライフサイクルでは、その中で定義された関数ポインターがそれぞれの関数を実装するために呼び出されます。重要なデータ構造 (sapi_globals) もあります。対応するマクロは SG(v)
typedef struct _sapi_globals_struct { void *server_context; sapi_request_info request_info; sapi_headers_struct sapi_headers; int64_t read_post_bytes; unsigned char post_read; unsigned char headers_sent; zend_stat_t global_stat; char *default_mimetype; char *default_charset; HashTable *rfc1867_uploaded_files; zend_long post_max_size; int options; zend_bool sapi_started; double global_request_time; HashTable known_post_content_types; zval callback_func; zend_fcall_info_cache fci_cache; } sapi_globals_struct;
cgi_main.c を振り返ると、cgi コード全体が合計 900 行を超えています。
zend_signal_startup 信号処理メソッド; (Linux 信号については後で説明します。ピットが大きすぎます)
sapi_startup(&cgi_sapi_module) を呼び出していくつかの処理を実行します。 sapi_model での初期化作業
... sapi_startup(&cgi_sapi_module); fastcgi = fcgi_is_fastcgi(); cgi_sapi_module.php_ini_path_override = NULL;
sapi_starup メソッドに従います
SAPI_API void sapi_startup(sapi_module_struct *sf) { sf->ini_entries = NULL // ini_entries设置null sapi_module = *sf; // 把传进来的结构体赋值给sapi_module // 上面有关于sap_module的 定义 sapi_module_struct sapi_module; //这里你可以理解为 初始化了sapi_module_struct #ifdef ZTS ts_allocate_fast_id(&sapi_globals_id, &sapi_globals_offset, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor); # ifdef PHP_WIN32 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); # endif #else sapi_globals_ctor(&sapi_globals); #endif #ifdef PHP_WIN32 tsrm_win32_startup(); #endif reentrancy_startup(); }
今のところ if 条件を無視して、最後に sapi_globals_ctor 関数に進みます
static void sapi_globals_ctor(sapi_globals_struct *sapi_globals) { memset(sapi_globals, 0, sizeof(*sapi_globals)); zend_hash_init(&sapi_globals->known_post_content_types, 8, NULL, _type_dtor, 1); php_setup_sapi_content_types(); }
memset は C 言語でメモリを初期化するネイティブ メソッドです
下面是 memset() 函数的声明。 void *memset(void *str, int c, size_t n) 参数 str -- 指向要填充的内存块。 c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。 n -- 要被设置为该值的字符数。 返回值 该值返回一个指向存储区 str 的指针。
上記により、 560 バイトの新しいメモリ
php_setup_sapi_content_types の内部実装は
/* {{{ php_startup_sapi_content_types */ int php_startup_sapi_content_types(void) { sapi_register_default_post_reader(php_default_post_reader); sapi_register_treat_data(php_default_treat_data); sapi_register_input_filter(php_default_input_filter, NULL); return SUCCESS; }
最後の reentrancy_startup は、スレッド セーフティがオンになっている場合にのみ有効な関数です
sapi_startup(&cgi_sapi_module); fastcgi = fcgi_is_fastcgi(); cgi_sapi_module.php_ini_path_override = NULL;
fcgi_is_fastcgi の実行を開始しますmethod
int fcgi_is_fastcgi(void) { if (!is_initialized) { return fcgi_init(); } else { return is_fastcgi; } }
is_initialized のデフォルトの初期値は 0
それでは、fcgi_init() 関数に進みますint fcgi_init(void) { if (!is_initialized) { #ifndef _WIN32 sa_t sa; socklen_t len = sizeof(sa); #endif zend_hash_init(&fcgi_mgmt_vars, 8, NULL, fcgi_free_mgmt_var_cb, 1); fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, "0", sizeof("0")-1); is_initialized = 1; #ifdef _WIN32 # if 0 /* TODO: Support for TCP sockets */ WSADATA wsaData; if (WSAStartup(MAKEWORD(2,0), &wsaData)) { fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError()); return 0; } # endif if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) && (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) && (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)) { char *str; DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT; HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE); SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL); str = getenv("_FCGI_SHUTDOWN_EVENT_"); if (str != NULL) { zend_long ev; HANDLE shutdown_event; ZEND_ATOL(ev, str); shutdown_event = (HANDLE) ev; if (!CreateThread(NULL, 0, fcgi_shutdown_thread, shutdown_event, 0, NULL)) { return -1; } } str = getenv("_FCGI_MUTEX_"); if (str != NULL) { zend_long mt; ZEND_ATOL(mt, str); fcgi_accept_mutex = (HANDLE) mt; } return is_fastcgi = 1; } else { return is_fastcgi = 0; } #else errno = 0; if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) { fcgi_setup_signals(); return is_fastcgi = 1; } else { return is_fastcgi = 0; } #endif } return is_fastcgi; }
fgi プロトコル関連のコンテンツを初期化します
推奨学習: 「PHP ビデオ チュートリアル
」
以上がPHP8 の基礎となるカーネル ソース コードである SAPI の詳細な分析 (1)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









php5 と php8 の違いは、パフォーマンス、言語構造、型システム、エラー処理、非同期プログラミング、標準ライブラリ関数、セキュリティの点です。詳細な紹介: 1. パフォーマンスの向上. PHP5 と比較して、PHP8 はパフォーマンスが大幅に向上しています. PHP8 では、高頻度の実行コードをコンパイルおよび最適化できる JIT コンパイラーが導入されており、それによって実行速度が向上しています; 2. 言語構造の改善、 PHP8 では、いくつかの新しい言語構造と関数が導入されており、PHP8 では名前付きパラメータがサポートされており、開発者はパラメータの順序などの代わりにパラメータ名を渡すことができます。

mysql 拡張機能を php8 に追加する手順は次のとおりです: 1. MySQL クライアント ライブラリをインストールします; 2. PHP 8 の開発ツールをインストールします; 3. MySQL 拡張機能のソース コードをダウンロードします; 4. MySQL 拡張機能をコンパイルしてインストールします; 5. MySQL 拡張機能; 6. Web サーバーのみを再起動します。

この記事では、apache2.4のインストール方法とphp8.0の設定方法を画像付きで詳しく紹介します。apache2.4+php8.0のインストールと設定方法を見てみましょう~

PHP8 は、mysqli と PDO を使用してデータベースに接続できます。詳細な紹介: 1. mysqli を使用して、データベース サーバー名、ユーザー名、パスワード、および接続するデータベース名を渡してデータベースに接続します。次に、`connect_error` 属性を使用して接続が成功したかどうかを確認し、接続が失敗した場合はエラー メッセージを出力します。最後に、`close()` メソッドを呼び出して接続を閉じます; 2. PDO を使用してデータベースに接続し、データベース サーバー名、パスワード、データベース名などを渡して接続します。

php8 データ型のメソッドには、文字列から整数への変換、整数から文字列への変換、文字列から浮動小数点数への変換、浮動小数点数から文字列への変換、配列から文字列への変換、文字列から配列への変換、およびブール値から整数への変換が含まれます。 . 整数からブール値への変換、変数の型の決定と変換。詳細な紹介: 1. 文字列から整数への変換には、intval() 関数と (int) 強制型変換が含まれます; 2. 整数から文字列への変換には、strval() 関数と (string) 強制型変換が含まれます; 3. 変換文字列を浮動小数点ポイントに変換するなどです。

この記事では、PHP 8 の JIT について説明し、JIT が解釈プロセスにどのように参加するかについて説明します。

php8 のパフォーマンス向上には、1. JIT コンパイラの導入、2. 関数呼び出しの最適化、3. ガベージ コレクション メカニズムの改善、4. 型システムの改善、5. 新しい言語機能、6. 文字列処理の最適化、7.配列処理の改善、8. 新しいメモリ管理メカニズムの導入、9. コード生成の最適化。詳細な紹介: 1. JIT コンパイラーの導入 PHP8 では、より効率的に実行するために PHP コードをマシンコードに変換できる動的コンパイル技術である JIT コンパイラーが導入されています; 2. 関数呼び出しの最適化など。

php8 の機能: 1. JIT コンパイラ; 2. 名前付きパラメータ; 3. 共用体型; 4. アノテーション; 5. コンストラクタ属性の強化; 6. 一致式; 7. nullsafe 演算子; 8. 型システムの改善; 9 、エラー処理の改善; 10. 一貫性の向上。詳細な紹介: 1. JIT コンパイラ、PHP8 は、PHP コードをネイティブ マシン コードにコンパイルするジャストインタイム コンパイル テクノロジを導入し、それによってプログラムの実行速度を向上させます; 2. 名前付きパラメータ、PHP8 は名前付きパラメータをサポートし、関数呼び出し時のパラメータ名など
