ホームページ >バックエンド開発 >PHPチュートリアル >PHP のライフサイクルを調べる
PHP のライフ サイクルは非常に複雑なプロセスであり、そのライフ サイクルは、使いこなしたい人が習得する必要があります。それ。主な内容は次のとおりです。
PHP の起動。 CLI または FPM を実行している場合は、C main()
が実行されます。 apxs2 SAPI (Apache 2) のように、ネットワーク サーバーへのモジュールとして実行する場合、Apache の起動直後に PHP が起動し、そのモジュール (PHP もその 1 つ) の起動シーケンスの実行を開始します。スタートアップは内部的に Module Startup Step と呼ばれます。 MINIT ステップとも略します。
PHP が開始されると、1 つまたは複数のリクエストの処理を待機します。 PHP CLI について話すとき、リクエストは 1 つだけです。実行する現在のスクリプトです。しかし、Web 環境について話す場合、それは PHP-FPM または Web サーバー モジュールである必要があります。PHP は複数のリクエストを次々に処理できます。すべては Web サーバーの構成方法によって異なります。無制限の数のリクエストを処理するように指示することも、プロセスをシャットダウンしてリサイクルする前に特定の数のリクエストを処理するように指示することもできます。 PHP は、新しいリクエストがスレッドで処理されるたびに、リクエスト開始ステップを実行します。これを #RINIT と呼びます。
関連する学習の推奨事項: PHP プログラミングの入門から熟練度まで
リクエストが処理され、(おそらく) コンテンツが生成されました。リクエストを閉じて、別のリクエストを処理する準備をします。クローズ要求は、リクエストクローズステップを呼び出します。これを #RSHUTDOWN と呼びます。 ·
X リクエスト (1 つ、数十、数千など) を処理した後、PHP は最終的に自動的にシャットダウンして終了します。 PHP プロセスのシャットダウンは、モジュール シャットダウン ステップと呼ばれます。略称は MSHUTDOWN です。
これらの手順を描くことができれば、次のようになります:
CLI 環境では、何でも簡単です。 : プロセスはリクエストを処理します。別の PHP スクリプトを開始して終了します。 CLI 環境は Web 環境を特殊化したものであり、より複雑です。
複数のリクエストを同時に処理するには、並列モデルを実行する必要があります。 PHP には 2 つのタイプがあります。
Use プロセス モデルに基づいて、オペレーティング システムは各 PHP インタープリターを独自のプロセスに分離します。このモデルは Unix では非常に一般的です。各リクエストは独自のプロセスに送られます。 PHP-CLI、PHP-FPM、および PHP-CGI はこのモデルを使用します。
スレッドベースのモデルでは、各 PHP インタープリターは、スレッド ライブラリを使用してスレッドに分離されます。このモデルは主に Windows オペレーティング システムで使用されますが、ほとんどの Unix でも使用できます。 PHP とその拡張機能を ZTS モードで構築する必要があります。
これはプロセスベースのモデルです:
これはスレッドベースのモデルです:
Note
拡張機能開発者にとって、PHP のマルチプロセス モジュールは選択肢にはなりません。それをサポートする必要があります。拡張機能がスレッド環境 (特に Windows 上) で実行できるようにする必要があり、そのようにプログラムする必要があります。
ご想像のとおり、PHP エンジンは複数のライフサイクル ポイントで拡張機能をトリガーします。これらを フック関数 と呼びます。拡張機能は、エンジンに登録するときに関数フックを宣言することで、特定のライフサイクル ポイントへの関心を宣言できます。
これらのフックは、PHP 拡張構造 (zend_module_entry
構造) を分析すると明確にわかります。
struct _zend_module_entry { unsigned short size; unsigned int zend_api; unsigned char zend_debug; unsigned char zts; const struct _zend_ini_entry *ini_entry; const struct _zend_module_dep *deps; const char *name; const struct _zend_function_entry *functions; int (*module_startup_func)(INIT_FUNC_ARGS); /* MINIT() */ int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); /* MSHUTDOWN() */ int (*request_startup_func)(INIT_FUNC_ARGS); /* RINIT() */ int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); /* RSHUTDOWN() */ void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); /* PHPINFO() */ const char *version; size_t globals_size; #ifdef ZTS ts_rsrc_id* globals_id_ptr; #else void* globals_ptr; #endif void (*globals_ctor)(void *global); /* GINIT() */ void (*globals_dtor)(void *global); /* GSHUTDOWN */ int (*post_deactivate_func)(void); /* PRSHUTDOWN() */ int module_started; unsigned char type; void *handle; int module_number; const char *build_id; };
次に、コードにどの種類のフックを記述する必要があるかを見てみましょう。
これは、PHP プロセスの起動ステップです。拡張された MINIT()
では、後続の各リクエストに必要な永続オブジェクトまたは情報をロードして割り当てます。それらのほとんどは読み取り専用オブジェクトとして割り当てられます。
MINIT()
では、スレッドやプロセスがまだポップアップしていないため、保護なしでグローバル変数に完全にアクセスできます。また、リクエストがまだ開始されていないため、リクエストにバインドされたメモリを割り当てることはできません。 MINIT()
ステップでは Zend のメモリ管理割り当てを使用することはありませんが、永続的な割り当てが使用されます。 emalloc()
ではなく、pemalloc()
です。そうしないとクラッシュが発生します。
MINIT()
では、実行エンジンがまだ開始されていないため、特別な注意を払わずにその構造にアクセスしようとしないでください。
拡張機能の INI エントリを登録する必要がある場合は、MINIT()
が正しいアプローチです。
後で使用するために読み取り専用の zend_string を登録したい場合は、永続的割り当てを使用してください。
割り当てる必要があるオブジェクトがリクエストの処理中に書き込まれる場合は、それらのメモリ割り当てをそのリクエストのスレッド固有のプールにコピーする必要があります。グローバル空間に安全に書き込むことができるのは、MINIT()
のみであることに注意してください。
注
メモリ管理、割り当て、およびデバッグは、メモリ管理の章の一部です。
php_module_startup() 関数では、MINIT()
が zend_startup_modules()
を通じてトリガーされます。
これは、PHP プロセスの終了ステップです。基本的には簡単です。ここでは、MINIT()
で使用したものとは逆のことを実行します。リソースを解放したり、INI 設定の登録を解除したりします。
もう一度注意してください: 実行エンジンは閉じられているため、ここではその変数にアクセスしないでください。
ここではリクエストが必要ないため、リソースを解放するために Zend Memory Management の efree()
または同様の関数を使用しないでください。ただし、永続的な割り当てを解放するには、pefree ( )
。
php_module_shutdown() 関数では、MSHUTDOWN()
が zend_destroy_modules()
の zend_shutdown()
によってトリガーされます。
先ほど確認したリクエストは、PHP がここで処理します。 #RINIT()
では、その正確なリクエストを処理するために必要なリソースを指示します。 PHP は、メモリ管理機能を提供するシェアードナッシング アーキテクチャです。
RINIT()
で、動的メモリを割り当てる必要がある場合は、Zend メモリ マネージャーを使用します。 emalloc()
を呼び出します。 Zend メモリ マネージャーは、ユーザーが割り当てたメモリを追跡し、リクエストが閉じられたときに、これを忘れた場合はリクエストにバインドされたメモリを解放しようとします (これは行うべきではありません)。
ここでは、永続的な動的メモリ、つまり libc の malloc()
や Zend の pemalloc()
をリクエストしないでください。ここで永続メモリをリクエストし、それを解放するのを忘れると、PHP が処理するリクエストが増えるにつれてリークが蓄積し、最終的にはプロセスがクラッシュし (カーネル OOM)、マシンのメモリが不足します。
また、ここではグローバル空間に書き込まないように注意してください。選択した並列モデルとして PHP がスレッド内で実行される場合、各スレッド プールのコンテキスト (すべてのリクエストが並行して処理される) を変更することになり、メモリをロックしないと競合状態がトリガーされる可能性もあります。全体像を把握したいなら、彼らを守らなければなりません。
注
グローバル スコープ管理については、専用の章で説明します。
php_request_startup() 関数では、RINIT()
が zend_activate_module()
によってトリガーされます。
これは、PHP リクエスト終了ステップです。 PHP はリクエストの処理を終えたところです。今度は、シェアードナッシング アーキテクチャとしてメモリの一部をクリーンアップします。後続のリクエストでは、現在のリクエストの内容を何も覚えてはいけません。それは簡単です。基本的に、ここで RINIT()
が使用していることと逆のことを行うことになります。リクエストによってバインドされているリソースを解放します。
ここではリクエストを使用しているため、Zend メモリ マネージャーの efree()
などを使用してリソースを解放する必要があります。解放するのを忘れてリークが発生した場合、デバッグ ビルドでメモリ マネージャーがプロセス stderr 上のリークしたポインターをログに記録し、それらを解放します。
ユーザー領域のシャットダウン関数 (register_shutdown_function()##) を実行した後、
RSHUTDOWN()
#PHP 出力バッファーをフラッシュした後
#max_execution_time を無効にした後 このフックはほとんど使用されません。これは
#RSHUTDOWN() の後に呼び出されますが、追加のエンジン コードが途中で実行されます。
特に RSHUTDOWN 後:
PHP スーパーグローバルが破棄されました
実行エンジンはシャットダウンされました
スレッド ライブラリは、スレッドがポップアップするたびにこのフックを呼び出します。複数のプロセスを使用する場合、PHP の起動時に、MINIT()
がトリガーされる前にのみこの関数が呼び出されます。
ここではあまり詳しくは説明しませんが、単にここでグローバル変数を初期化するだけです (通常は 0 に初期化されます)。グローバル管理については、専用の章で詳しく説明します。
グローバル変数はリクエストごとにクリーンアップされないことに注意してください。 (おそらく) 新しいリクエストごとにそれらをリセットする必要がある場合は、そのようなプロセスを RINIT()
に入れる必要があります。
注
グローバル スコープ管理については、専用の章で詳しく紹介されています。
スレッド ライブラリでは、スレッドが終了するたびにこのフックが呼び出されます。マルチスレッドを使用する場合、この関数は PHP の終了時 (MSHUTDOWN()
) に 1 回呼び出されます。
ここではあまり詳細を説明せずに、ここでグローバル変数を単純に初期化解除できます。通常は何もする必要はありませんが、グローバル (GINIT()
) を構築している場合は、リソースが割り当てられたら、このステップでリソースを解放する必要があります。
グローバル経営については、別章で詳しく紹介します。
グローバル変数は各リクエスト後にクリアされないことに注意してください。つまり、GSHUTDOWN()
は RSHUTDOWN()
の一部として呼び出されません。
注
グローバル スコープ管理については、専用の章で詳しく紹介されています。
このフックは非常に特殊で、エンジンによって自動的にトリガーされることはありません。エンジンに情報を要求した場合にのみトリガーされます。拡大。典型的な例は、phpinfo()
の呼び出しです。次に、この関数が実行され、現在の拡張に関する特別な情報がストリームに出力されます。
つまり、phpinfo()
は情報を表示します。
この関数は、php --ri pib
などのリフレクション スイッチの 1 つを使用する CLI 経由、またはユーザーランド呼び出し ini_get_all()
経由で呼び出すこともできます。
これを空白のままにすることもできます。その場合、拡張機能の名前のみが表示され、他は何も表示されません (これは MINFO() の一部であるため、INI 設定は表示されない場合があります)。
RINIT()
と RSHUTDOWN()
は拡張機能内で何千回もトリガーされるため、特に重要です。 PHP ステップが Web (CLI ではなく) 用であり、無制限のリクエストを処理するように構成されている場合、RINIT()/RSHUTDOWN()
グループは無制限に呼び出されます。
メモリ管理にもう一度注目していただきたいと思います。リクエストの処理中 (RINIT()
と RSHUTDOWN()
の間) に小さなバイトがリークすることになり、フル負荷のサーバーに深刻な影響を及ぼします。このため、このような割り当てには Zend Memory Manager を使用し、メモリ レイアウトをデバッグする準備をしておくことをお勧めします。シェアードナッシング アーキテクチャの一部として、PHP は各リクエストの終了時に要求されたメモリを忘れて解放しますが、これは PHP の内部設計によるものです。
また、クラッシュ信号が SIGSEGV (不正なメモリ アクセス) の場合、プロセス全体がクラッシュします。 PHP がマルチプロセス エンジンとしてスレッドを使用している場合、他のすべてのスレッドもクラッシュし、サーバーがクラッシュする可能性もあります。
注意
C 言語は PHP 言語ではありません。 C では、プログラム内のエラーによりプログラムがクラッシュして終了する可能性があります。
エンジンがコードを起動するタイミングがわかったので、エンジンにフックするために置き換えることができる注目に値する関数ポインターもあります。これらのポインターはグローバル変数であるため、MINIT()
ステップに置き換えて、MSHUTDOWN()
ステップに戻すことができます。
興味深いものは次のとおりです:
##int (
gc_collect_cycles)(void)*tsrm_thread_begin_func_t)(THREAD_T thread_id)*
zend_error_cb)(int 型、const char
error_filename、const uint error_lineno、const charライフタイム、Zend/zend.h:
他にもありますが、上記は PHP を設計するときに最も重要です。拡張機能が必要になる場合があります。読みやすい名前ですので、詳しい説明は省略します。
さらに詳しい情報が必要な場合は、PHP ソース コードを調べて、いつどのようにトリガーされるかを確認できます。
以上がPHP のライフサイクルを調べるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。