前の記事 に続いて、php のライフサイクルについて説明し、どのフックが何を行うために拡張されているかを見てみましょう。 php ライフサイクルには、モジュール初期化ステージphp_module_startup
、リクエスト初期化ステージphp_request_startup
、スクリプト実行ステージphp_execute_script
、リクエストシャットダウンステージの5つのステージがあります。 php_request_shutdown
、モジュールシャットダウンフェーズphp_module_shutdown
、cliモードで以下に紹介します。
php_module_startup
まず、この段階で何が行われるかを見てみましょう。php エントリ ファイルがどこにあるかわからない場合は、gdb を使用してコール スタック、gdb ./ php
php_module_startup
ブレーク ポイントで実行し、コール スタックを確認します。
b php_module_startup (gdb) r test.php bt php_module_startup (sf=0x1406460 <cli_sapi_module>, additional_modules=0x0, num_additional_modules=0) at /www/test/php/php-7.4.3/main/main.c:2098 #1 0x00000000008bae7c in php_cli_startup ( sapi_module=0x1406460 <cli_sapi_module>) at /www/test/php/php-7.4.3/sapi/cli/php_cli.c:407 #2 0x00000000008bcc80 in main (argc=2, argv=0x1425af0) at /www/test/php/php-7.4.3/sapi/cli/php_cli.c:1323
はっきりとわかります。コール スタック内の実行プロセスを確認するには、/main/main.c ファイルに移動します。gdb を使用して、ステップごとに確認することもできます。ここでは、PHP 拡張機能に関連するいくつかの場所を示します。ガベージ コレクション、リクエストの初期化、登録された定数など、ここで実行されます。php.ini 設定ファイルの読み込みなど。
まずモジュールの読み込み方法を見てみましょう
/* startup extensions statically compiled in */ if (php_register_internal_extensions_func() == FAILURE) { php_printf("Unable to start builtin modules\n"); return FAILURE; }
ここで読み込みますphp の組み込みモジュールです。ここにはコア関数のみが掲載されています。最初に依存関係を確認してください
/* Check module dependencies */ if (module->deps) { const zend_module_dep *dep = module->deps; while (dep->name) { if (dep->type == MODULE_DEP_CONFLICTS) { name_len = strlen(dep->name); lcname = zend_string_alloc(name_len, 0); zend_str_tolower_copy(ZSTR_VAL(lcname), dep->name, name_len); if (zend_hash_exists(&module_registry, lcname) || zend_get_extension(dep->name)) { zend_string_efree(lcname); /* TODO: Check version relationship */ zend_error(E_CORE_WARNING, "Cannot load module '%s' because conflicting module '%s' is already loaded", module->name, dep->name); return NULL; } zend_string_efree(lcname); } ++dep; } }
if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type)==FAILURE) { zend_hash_del(&module_registry, lcname); zend_string_release(lcname); EG(current_module) = NULL; zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load", module->name); return NULL; }
これが組み込みモジュールをロードする原則です。次に、ini に拡張機能をロードする方法を見てみましょう
php_ini_register_extensions();
zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb);
この関数を使用してロード
php_load_extension(char *filename, int type, int start_now)
これは、組み込みモジュールをロードする機能も実行します。
は、モジュール関数 function を登録するために module->functions
を呼び出しています。これで、関数関数を helloworld_functions
ここで
zend_module_entry helloworld_module_entry = { STANDARD_MODULE_HEADER, "helloworld", /* Extension name */ helloworld_functions, /* zend_function_entry */ PHP_MINIT(helloworld), /* PHP_MINIT - Module initialization */ NULL, /* PHP_MSHUTDOWN - Module shutdown */ PHP_RINIT(helloworld), /* PHP_RINIT - Request initialization */ NULL, /* PHP_RSHUTDOWN - Request shutdown */ PHP_MINFO(helloworld), /* PHP_MINFO - Module info */ PHP_HELLOWORLD_VERSION, /* Version */ PHP_MODULE_GLOBALS(pib), NULL, NULL, NULL, STANDARD_MODULE_PROPERTIES_EX };# に記述する必要がある理由がわかりました。 ##ここで、拡張機能のいくつかのフック関数を見てみましょう
/* start Zend extensions */ zend_startup_extensions();ここでの核心は
func(element->data)つまり、拡張機能の実行です
Function<pre class="brush:php;toolbar:false">element=l->head;
while (element) {
next = element->next;
if (func(element->data)) {
DEL_LLIST_ELEMENT(element, l);
}
element = next;
}</pre>
これで
フックは多くの初期化関数を実行できることがわかりましたカスタム拡張関数クラスを登録する方法と拡張変数をphpに書き込む方法。 ini 、php の組み込み関数を書き換える方法、<pre class="brush:php;toolbar:false">original = zend_hash_str_find_ptr(CG(function_table), "var_dump", sizeof("var_dump")-1);
if (original != NULL) {
original->internal_function.handler = my_overwrite_var_dump;
}
zend_class_entry person;
INIT_CLASS_ENTRY(person,CLASS_NAME,person_functions);
zend_register_internal_class_ex(&person,NULL);</pre>
ここでは var_dump 関数を書き換え、person クラスを登録します。まずここで紹介します。
で php を渡す方法を紹介します。字句解析によるコード 構文解析により AST が生成され、zend 仮想マシンによる呼び出し用のオペコード命令がコンパイルされます。 推奨学習: 「
PHP ビデオ チュートリアル