ホームページ >バックエンド開発 >PHPチュートリアル >PHP カーネルの学習 - PHP ライフサイクル

PHP カーネルの学習 - PHP ライフサイクル

WBOY
WBOYオリジナル
2016-06-13 12:20:25980ブラウズ

PHP カーネルの学習 - PHP ライフ サイクル

すべての始まり: SAPI インターフェイス

SAPI (Server Application Programming Interface) は、PC と同様に、特定の PHP アプリケーション用のプログラミング インターフェイスを指します。どのオペレーティング システムがインストールされているかに関係なく、PC インターフェイス仕様を満たしている限り、PHP スクリプトを実行する方法は数多くあります。Web サーバー経由、コマンド ライン直下、または他のプログラムに埋め込まれています。 。

通常、Apache や Nginx などの Web サーバーを使用して PHP スクリプトをテストするか、コマンド ラインで PHP インタープリタ プログラムを通じてスクリプトを実行します。 スクリプトが実行されると、Web サーバーが応答し、ブラウザーは応答情報を表示するか、コマンド ラインの標準出力に内容を表示します。

PHP インタープリターがどこにあるかを気にすることはほとんどありません。 Web サーバーとコマンドライン プログラムを介したスクリプトの実行は非常に異なって見えますが、ワークフローは実際には同じです。コマンド ライン パラメーターは、PHP インタープリターによって実行されるスクリプトに渡されます。これは、URL を介して PHP ページをリクエストするのと同じです。スクリプトの実行が完了すると応答結果が返されますが、ターミナル上にはコマンドラインの応答結果が表示されます。

スクリプトの実行は、SAPI インターフェースの実装から始まります。たとえば、Apache の mod_php SAPI 実装は、Apache から取得した一部の情報を初期化し、コンテンツを出力するときにコンテンツを Apache に返す必要があるというだけです。

次のセクションでは、いくつかの一般的な SAPI 実装について詳しく説明します。

開始と終了

PHP の実行が開始されると、リクエストを処理する前の開始フェーズとリクエスト後の終了フェーズの 2 つの主なフェーズが実行されます。 開始フェーズには 2 つのプロセスがあります。最初のプロセスはモジュール初期化フェーズ (MINIT) です。このプロセスは、SAPI ライフ サイクル全体 (Apache の開始後のライフ サイクル全体、または Apache の実行プロセス全体など) で 1 回だけ実行されます。コマンドラインプログラム)。 2 番目のプロセスはモジュール アクティベーション フェーズ (RINIT) で、リクエスト フェーズで発生します。たとえば、URL を通じてページがリクエストされた場合、各リクエストの前にモジュール アクティベーション (RINIT リクエストの開始) が実行されます。 たとえば、PHP がいくつかの拡張モジュールを登録すると、MINIT ステージ中にすべてのモジュールの MINIT 関数がコールバックされます。 モジュールはこの段階で、定数の登録、モジュールで使用されるクラスの定義などの初期化作業を実行できます。 モジュールが実装されると、これらのコールバック関数は次のマクロを通じて実装できます:

<span style="color: #000000;">PHP_MINIT_FUNCTION(myphpextension){    </span><span style="color: #008000;">//</span><span style="color: #008000;"> 注册常量或者类等初始化操作</span>    <span style="color: #0000ff;">return</span><span style="color: #000000;"> SUCCESS; }</span>

リクエストが到着した後、PHP はスクリプトを実行するための基本環境を初期化します。 PHP 実行の保存を含む実行環境 プロセス内の変数名と値の内容のシンボル テーブル、および現在のすべての関数、クラス、その他の情報のシンボル テーブル。次に、PHP はすべてのモジュールの RINIT 関数を呼び出します。この段階で、各モジュールは、MINIT コールバック関数と同様のいくつかの関連操作を実行できます。

リクエスト処理 その後、PHPはスクリプトを最後まで実行するか、exit()関数やdie()関数を呼び出すことで終了フェーズに入ります。開始ステージに対応して、終了ステージも 2 つのステージに分かれています。1 つはリクエストの完了後にモジュールを非アクティブ化するもの (RSHUTDOWN、RINIT に対応)、もう 1 つは SAPI ライフサイクルの終了時にモジュールを閉じるものです ( Web サーバーが終了するか、コマンド ライン スクリプトが実行されて終了します) (MSHUTDOWN、MINIT に対応)。
<span style="color: #000000;">PHP_RINIT_FUNCTION(myphpextension){    </span><span style="color: #008000;">//</span><span style="color: #008000;"> 例如记录请求开始时间    </span><span style="color: #008000;">//</span><span style="color: #008000;"> 随后在请求结束的时候记录结束时间。这样我们就能够记录下处理请求所花费的时间了</span>    <span style="color: #0000ff;">return</span><span style="color: #000000;"> SUCCESS; }</span>

シングルプロセス SAPI ライフサイクル
<span style="color: #000000;">PHP_RSHUTDOWN_FUNCTION(myphpextension){    </span><span style="color: #008000;">//</span><span style="color: #008000;"> 例如记录请求结束时间,并把相应的信息写入到日至文件中。</span>    <span style="color: #0000ff;">return</span><span style="color: #000000;"> SUCCESS; }</span>
CLI/CGI モード PHP はシングルプロセス SAPI モードに属します。このタイプのリクエストは、リクエストを一度処理した後に閉じられます。つまり、次のリンクのみを経由します。 開始 - リクエストの開始 - リクエストのクローズ - 終了 SAPI インターフェイスの実装はライフ サイクルを完了します。以下の図に示すように:

単一プロセス SAPI ライフサイクル

上の図はとても簡単です。ただ、PHP はさまざまな段階の間でも多くの作業を実行します。

Start

各モジュールのモジュール初期化を呼び出す前に、以下を含む初期化プロセスがあります:

いくつかのグローバル変数を初期化します

  • ほとんどの場合、ここで初期化されたグローバル変数は NULL に設定されますが、zuf (zend_utility_functions) を Take zuf に設定するなどの例外があります。例として .printf_function = php_printf は、zend_startup 関数の zend_printf に割り当てられ、zend_printf 関数は通常、プログラム呼び出しを表示する debug_print_backtrace として使用されます。 stack はこれを使用して関連情報を出力します。

いくつかの定数を初期化する

  • ここでの定数は、PHP 独自の定数の一部です。これらの定数は、プログラム内でハードコーディングされています。 PHP_VERSION、PEAR_EXTENSION_DIR などの構成ヘッダー ファイルに記述されるか、config.w32.h ファイルに記述されます。
    • 初始化Zend引擎和核心组件

    前面提到的zend_startup函数的作用就是初始化Zend引擎,这里的初始化操作包括内存管理初始化、 全局使用的函数指针初始化(如前面所说的zend_printf等),对PHP源文件进行词法分析、语法分析、 中间代码执行的函数指针的赋值,初始化若干HashTable(比如函数表,常量表等等),为ini文件解析做准备, 为PHP源文件解析做准备,注册内置函数(如strlen、define等),注册标准常量(如E_ALL、TRUE、NULL等)、注册GLOBALS全局变量等。

    • 解析php.ini

    php_init_config函数的作用是读取php.ini文件,设置配置参数,加载zend扩展并注册PHP扩展函数。此函数分为如下几步: 初始化参数配置表,调用当前模式下的ini初始化配置,比如CLI模式下,会做如下初始化:

    INI_DEFAULT(<span style="color: #800000;">"</span><span style="color: #800000;">report_zend_debug</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">0</span><span style="color: #800000;">"</span><span style="color: #000000;">);INI_DEFAULT(</span><span style="color: #800000;">"</span><span style="color: #800000;">display_errors</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">1</span><span style="color: #800000;">"</span>);

    不过在其它模式下却没有这样的初始化操作。接下来会的各种操作都是查找ini文件:

    1. 判断是否有php_ini_path_override,在CLI模式下可以通过-c参数指定此路径(在php的命令参数中-c表示在指定的路径中查找ini文件)。
    2. 如果没有php_ini_path_override,判断php_ini_ignore是否为非空(忽略php.ini配置,这里也就CLI模式下有用,使用-n参数)。
    3. 如果不忽略ini配置,则开始处理php_ini_search_path(查找ini文件的路径),这些路径包括CWD(当前路径,不过这种不适用CLI模式)、 执行脚本所在目录、环境变量PATH和PHPRC和配置文件中的PHP_CONFIG_FILE_PATH的值。
    4. 在准备完查找路径后,PHP会判断现在的ini路径(php_ini_file_name)是否为文件和是否可打开。 如果这里ini路径是文件并且可打开,则会使用此文件, 也就是CLI模式下通过-c参数指定的ini文件的优先级是最高的, 其次是PHPRC指定的文件,第三是在搜索路径中查找php-%sapi-module-name%.ini文件(如CLI模式下应该是查找php-cli.ini文件), 最后才是搜索路径中查找php.ini文件。
    • 全局操作函数的初始化

    php_startup_auto_globals函数会初始化在用户空间所使用频率很高的一些全局变量,如:$_GET、$_POST、$_FILES等。 这里只是初始化,所调用的zend_register_auto_global函数也只是将这些变量名添加到CG(auto_globals)这个变量表。

    php_startup_sapi_content_types函数用来初始化SAPI对于不同类型内容的处理函数, 这里的处理函数包括POST数据默认处理函数、默认数据处理函数等。

    • 初始化静态构建的模块和共享模块(MINIT)

    php_register_internal_extensions_func函数用来注册静态构建的模块,也就是默认加载的模块, 我们可以将其认为内置模块。在PHP5.3.0版本中内置的模块包括PHP标准扩展模块(/ext/standard/目录, 这里是我们用的最频繁的函数,比如字符串函数,数学函数,数组操作函数等等),日历扩展模块、FTP扩展模块、 session扩展模块等。这些内置模块并不是一成不变的,在不同的PHP模板中,由于不同时间的需求或其它影响因素会导致这些默认加载的模块会变化, 比如从代码中我们就可以看到mysql、xml等扩展模块曾经或将来会作为内置模块出现。

    模块初始化会执行两个操作: 1. 将这些模块注册到已注册模块列表(module_registry),如果注册的模块已经注册过了,PHP会报Module XXX already loaded的错误。 1. 将每个模块中包含的函数注册到函数表( CG(function_table) ),如果函数无法添加,则会报 Unable to register functions, unable to load。

    在注册了静态构建的模块后,PHP会注册附加的模块,不同的模式下可以加载不同的模块集,比如在CLI模式下是没有这些附加的模块的。

    在内置模块和附加模块后,接下来是注册通过共享对象(比如DLL)和php.ini文件灵活配置的扩展。

    在所有的模块都注册后,PHP会马上执行模块初始化操作(zend_startup_modules)。 它的整个过程就是依次遍历每个模块,调用每个模块的模块初始化函数, 也就是在本小节前面所说的用宏PHP_MINIT_FUNCTION包含的内容。

    • 禁用函数和类

    php_disable_functions函数用来禁用PHP的一些函数。这些被禁用的函数来自PHP的配置文件的disable_functions变量。 其禁用的过程是调用zend_disable_function函数将指定的函数名从CG(function_table)函数表中删除。

    php_disable_classes 関数は、一部の PHP クラスを無効にするために使用されます。これらの無効なクラスは、PHP 構成ファイルの disable_classes 変数から取得されます。 無効化処理は、zend_disable_class 関数を呼び出して、指定されたクラス名を CG (class_table) クラス テーブルから削除します。

    ACTIVATION

    ファイル関連のコンテンツを処理した後、PHP は php_request_startup を呼び出してリクエストの初期化操作を実行します。 リクエスト初期化操作は、図に示されている各モジュールのリクエスト初期化関数の呼び出しに加えて、他の多くの作業も実行します。主な内容は次のとおりです。

    • Zend をアクティブ化します。 Engine

    gc_reset 関数はガベージ コレクション メカニズムをリセットするために使用されます。もちろん、これは PHP5.3 以降でのみ使用できます。

    init_compiler 関数は、コンパイル プロセス中にオペコードが配置される配列をクリアしたり、コンパイルに使用されるデータ構造を準備したりするなど、コンパイラーを初期化するために使用されます。

    init_executor 関数は、中間コードの実行プロセスを初期化するために使用されます。 コンパイル プロセス中、関数リスト、クラス リストなどがコンパイル時にグローバル変数に保存され、実行プロセスの準備時に、これらのリストは次のように実行されるグローバル変数に割り当てられます。 function_table) ; 中間コードは PHP の実行仮想スタックで実行され、これらのスタックは初期化中に一緒に初期化されます。 スタックに加えて、変数を格納するシンボルテーブル(EG(symbol_table))は50要素のハッシュテーブルに初期化され、オブジェクトを格納するEG(objects_store)は1024要素で初期化されます。上記の変数の一部に加えて、PHP の実行環境にはエラー処理、例外処理などもあり、これらはすべてここで初期化されます。 php.ini で設定された zend_extensions も調べられ、ここで activate 関数が呼び出されます。

    • SAPI をアクティブにする

    sapi_activate 関数は、SG (sapi_headers) と SG (request_info) を初期化し、HTTP のコンテンツを設定するために使用されます。たとえば、リクエスト メソッドが HEAD の場合、SG(request_info).headers_only=1 を設定します。この関数の最も重要な操作は、リクエストされたデータを処理することであり、最終的に sapi_module.default_post_reader を呼び出します。 sapi_module.default_post_reader は、前のモジュールの初期化で php_startup_sapi_content_types 関数を通じて登録されました。デフォルトの処理関数は、main/php_content_types.c ファイル内の php_default_post_reader 関数です。 この関数は、POST の生データを $HTTP_RAW_POST_DATA 変数に書き込みます。

    ポストデータの処理後、PHP は sapi_module.read_cookies を通じて Cookie 値を読み取ります。CLI モードでは、この関数の実装は sapi_cli_read_cookies ですが、関数本体には NULL が 1 つだけ返されます。

    現在のモードでアクティブ化関数が設定されている場合は、この関数を実行して SAPI をアクティブ化します。この関数ポインタは NULL に設定されます。

    • 環境の初期化

    ここでの環境の初期化とは、ユーザー空間で使用する必要があるいくつかの環境変数の初期化を指します。サーバー環境、リクエストデータ環境などが含まれます。 実際に使用する変数は、$_POST、$_GET、$_COOKIE、$_SERVER、$_ENV、$_FILES です。 sapi_module.default_post_reader と同様に、sapi_module.treat_data の値も、モジュールの初期化中に php_startup_sapi_content_types 関数を通じて登録されます。デフォルトのデータ処理関数は、main/php_variables.c ファイル内の php_default_treat_data 関数です。

    $_COOKIE を例にとると、php_default_treat_data 関数は区切り文字に基づいてすべての Cookie を分割し、対応する変数に割り当てます。

    • モジュールリクエストの初期化

    PHP は、zend_activate_modules 関数を通じてモジュールリクエストの初期化を実装します。つまり、図で各拡張機能の RINIT を呼び出すことがわかります。 この関数は、 module_registry 変数に登録されているすべてのモジュールを走査し、その RINIT メソッドを呼び出すことによって、モジュールの要求初期化操作を実装します。

    Run

    php_execute_script 関数には、PHP スクリプトを実行するプロセス全体が含まれています。

    PHP ファイルを解析して実行する必要がある場合、実行前ファイル、現在実行する必要があるメイン ファイル、実行後ファイルを含む 3 つのファイルを実行する必要がある場合があります。 2 つの非現行ファイルは、auto_prepend_file パラメーターと auto_append_file パラメーターを使用して php.ini ファイルに設定できます。 これら 2 つのパラメータが空に設定されている場合、対応する実行可能ファイルは無効になります。

    解析して実行する必要があるファイルの場合、字句解析、構文解析、中間コード生成操作が zend_compile_file (compile_file 関数) によって実行され、このファイルのすべての中間コードが返されます。 解析されたファイルが有効な中間コードを生成した場合は、zend_execute (実行関数) を呼び出して中間コードを実行します。 実行中に例外が発生し、ユーザーがこれらの例外の処理を定義している場合、これらの例外処理関数が呼び出されます。 すべての操作が処理された後、PHP は EG (return_value_ptr_ptr) を通じて結果を返します。

    DEACTIVATION

    PHP がリクエストを閉じるプロセスは、php_request_shutdown 関数に存在するいくつかの終了操作のセットです。 このコレクションには次のものが含まれます:

    1. register_shutdown_function() を通じて登録されたすべての関数を呼び出します。シャットダウン時に呼び出されるこれらの関数はユーザー空間に追加されました。 簡単な例として、スクリプト エラーが発生したときに統合関数を呼び出して、ユーザーにわかりやすいページを提供できます。これは Web の 404 ページに似ています。
    2. 利用可能なすべての __destruct 関数を実行します。 ここでのデストラクタには、オブジェクト プール内のすべてのオブジェクトのデストラクタ (EG (objects_store)) と EG の各要素のデストラクタ (symbol_table) が含まれます。
    3. すべての出力をフラッシュします。これも文字列を出力するプロセスですが、この文字列は特定の仕様に準拠している可能性があります。
    4. 各モジュールのシャットダウン要求メソッドをトラバースし、モジュールの要求シャットダウン操作を実行します。
    5. 各拡張機能の post_deactivate_func 関数を呼び出し、sapi_deactivate(sapi_headers)、SG(request_info)、を介して SAPI を閉じます。など。
    6. ストリーム ラッパーを閉じ、ストリーム フィルターを閉じます。
    7. 終了
    8. ついに終了です。
    9. flush
    10. sapi_flush は、sapi_module.flush を呼び出します。 CLI モードで fflush 関数にアクセスします。

    Zend エンジンを閉じます

    zend_shutdown は Zend エンジンをシャットダウンします。 >このとき、各モジュールのシャットダウンモジュール操作を実行する必要があります。もちろん、モジュールを閉じるメソッドも呼び出す zend_hash_graceful_reverse_destroy 関数があります。 module_registry が初期化されるときに設定され、ZEND_MODULE_DTOR マクロは module_destructor 関数に対応します。 module_shutdown_func メソッドは、PHP_RSHUTDOWN_FUNCTION マクロによって生成される関数です。
    • すべてのモジュールを閉じた後、PHP はグローバル関数テーブルを破棄し続けます。グローバル クラス テーブルの破棄、グローバル変数テーブルの販売など。zend_extensions から zend_shutdown_extensions までのすべての要素をスキャンし、各拡張機能の shutdown 関数を呼び出します。 マルチプロセス SAPI ライフサイクル
    通常、PHP は、PHP リクエストを処理するために Apache のモジュールとしてコンパイルされます。 Apache は通常、マルチプロセス モードを採用しており、Apache が起動されると、各プロセスは独立したメモリ領域を持ちます。ただし、各プロセスの開始フェーズのみが発生します。プロセスがフォークした後、プロセスの存続期間中に複数のリクエストが処理される可能性があります。 シャットダウン フェーズは、Apache がシャットダウンされるかプロセスが終了した後にのみ発生し、これら 2 つのフェーズの間で、リクエストの開始とリクエストのシャットダウン フェーズがリクエストごとに繰り返されます。 以下の図に示すように:

    • マルチプロセス SAPI ライフサイクル

    マルチスレッド SAPIライフサイクル

    マルチスレッドモードは、マルチプロセスのプロセスに似ていますが、プロセスのライフサイクル全体でリクエストの開始と終了のプロセスが

    並行して繰り返される

    という点が異なります。

    マルチスレッド SAPI ライフサイクル
    からの抜粋: http://www.php-internals.com /book/?p= chapt02/02-01-php-life-cycle-and-zend-engine

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。