この記事では、PHP コードがどのように解釈および実行されるか、および PHP スクリプト実行のライフサイクルについて学びます。
概要
PHPサービスの起動。厳密に言えば、PHP 関連のプロセスは、Apache の起動時に手動で開始する必要はありません。もちろん、PHP サービスを再起動する必要がある場合は、PHP サービスを手動で再起動することもできます。たとえば、オペコードを有効にして正式な環境でコードを更新した後、PHP を再起動して PHP コードを再コンパイルする必要があります。
マクロの観点から見ると、PHP カーネルの実装は、入力データを受け取り、内部で対応する処理を実行し、結果を出力することです。 PHP カーネルの場合、記述した PHP コードはカーネルによって受信された入力データであり、コード データを受信した後、PHP カーネルは記述したコードに対してコード解析と演算実行を実行し、最終的に対応する演算結果を返します。
ただし、通常の C 言語コードとは異なり、PHP コードを実行するには、まず PHP コードを機械語に「変換」して、対応する機能を実行する必要があります。 「翻訳」ステップを実行するには、PHP カーネルが字句解析、構文解析、その他のステップを実行する必要があります。最後に、PHP カーネルの Zend Engine に渡されて、順次実行されます。
字句分析
PHPコードを「ユニット」(TOKEN)に分割する
構文解析
「ユニット」を Zend Engine の実行可能オペレーションに変換します
Zend Engineの実行
構文解析で得られた演算を順番に実行します
すべての PHP プログラム (CGI/CLI) は SAPI (サーバー アプリケーション プログラミング インターフェイス) インターフェイスから始まります。 SAPI は、特定の PHP アプリケーションのプログラミング インターフェイスを指します。たとえば、Apache の mod_php です。
PHP は実行開始後に 2 つの主なフェーズを経ます。リクエストを処理する前の開始フェーズとリクエストの後の終了フェーズです。
開始フェーズ
PHP の初期段階全体は、モジュールの初期化とモジュールのアクティブ化という 2 つの段階を経ます。
ミニット
つまり、Apache/Nginx の起動後のライフサイクル全体、またはコマンドライン プログラムの実行プロセス全体で発生するモジュールの初期化フェーズです。このフェーズは 1 回だけ発生します
。RINIT
モジュールのアクティベーションはリクエストフェーズ中に発生します。定数の登録、モジュールで使用されるクラスの定義など、いくつかの初期化作業を実行します。
モジュールは、実装中に次のマクロを通じてこれらのコールバック関数を実装できます:
PHP スクリプトのリクエストが処理された後、PHP は通常、スクリプトが最後まで実行されるか、exit または die 関数が呼び出されたときに終了フェーズに入ります。
エンドステージ
PHP の終了フェーズは、モジュールの非アクティブ化とモジュールの終了の 2 つの部分に分かれています。
RSHUTDOWN
モジュールを無効にする(RINITに対応)
MSHUTDOWN
モジュール(MINITに相当)を閉じます
CLI/CGI モード PHP はシングルプロセス SAPI モードに属します。これは、PHP スクリプトが一度実行された後に閉じられ、すべての変数と関数が使用できなくなることを意味します。つまり、CGI モードでは、同じ PHP ファイルの変数を他の PHP ファイルで使用することはできません。
シングルスレッド PHP の SAPI ライフサイクルを見てみましょう。
シングルスレッド SAPI ライフサイクル
:
各拡張機能の MINIT モジュールを呼び出して初期化します
test.php をリクエストします
各拡張機能の RINIT モジュールを呼び出してアクティブ化します
test.php を実行します
各拡張機能の RSHUTDOWN 非アクティブ化モジュールを呼び出します
test.php の実行後に変数とメモリをクリーンアップします
各拡張機能 MSHUTDOWN を呼び出す モジュールを閉じる
PHP の実行を停止する
上記は簡単な実行プロセスですが、以下にいくつか追加します。
PHP には、各モジュールのモジュール初期化を呼び出す前に、次のような初期化プロセスがあります:
いくつかのグローバル変数を初期化します
ほとんどの場合、それらは NULL に設定されます。
いくつかの定数を初期化する
ここでの定数は、PHP 独自の定数の一部です。
Zend エンジンとコアコンポーネントを初期化します
ここでの初期化操作には、メモリ管理の初期化、グローバル関数ポインタの初期化、字句解析、PHP ソース ファイルの構文解析、中間コード実行のための関数ポインタの割り当て、および複数の HashTable の初期化が含まれます (関数テーブル、定数テーブルなど)、ini ファイル解析の準備、PHP ソースファイル解析の準備、組み込み関数、標準定数、GLOBALS グローバル変数などの登録
php.iniの解析
php.iniファイルを読み取り、構成パラメータを設定し、zend拡張機能をロードし、PHP拡張機能を登録します。
グローバル操作関数の初期化
$_GET、$_POST、$_FILES など、ユーザー空間で頻繁に使用されるいくつかのグローバル変数を初期化します。
初始化静态构建的模块和共享模块(MINIT)
初始化默认加载的模块。
模块初始化执行操作:
将模块注册到已注册模块列表
将每个模块中包含的函数注册到函数表
禁用函数和类
会调用zend_disable_function函数将PHP的配置文件中的disable_functions变量代表的函数从CG(function_table)函数表中删除。
激活Zend引擎
使用init_compiler函数来初始化编译器。
激活SAPI
使用sapi_activate函数来初始化SG(sapi_headers)和SG(request_info),并且针对HTTP请求的方法设置一些内容。
环境初始化
初始化在用户控件需要用到的一些环境变量。包括服务器环境、请求数据环境等。
模块请求初始化
PHP调用zend_activate_modules函数遍历注册在module_registry变量中的所有模块,调用其RINIT方法方法实现模块的请求初始化操作。
在处理了文件相关的内容后,PHP会调用php_request_startup做请求初始化操作:
<p> 激活Zend引擎<br /> 激活SAPI<br /> 环境初始化<br /> 模块请求初始化</p>
代码的运行
以上所有准备工作完成后,就开始执行PHP程序。PHP通过zend_compile_file做词法分析、语法分析和中间代码生成操作,返回此文件的所有中间代码。如果解析的文件有生成有效的中间代码,则调用zend_excute执行中间代码。。如果在执行过程中出现异常并且用户有定义对这些异常的处理,则调用这些异常处理函数。在所有的操作都处理完后,PHP通过EG(return_value_ptr_ptr)返回结果。
DEACTIVATION(关闭请求)
PHP关闭请求的过程是一个若干个关闭操作的集合,这个集合存在于php_request_shutdown函数中。这个包括:
<p>调用所有通过register_shutdown_function()注册的函数。这些在关闭时调用的函数是在用户空间添加进来的。<br />执行所有可用的__destruct函数。这里的析构函数包括在对象池(EG(objects_store)中的所有对象的析构函数以及EG(symbol_table)中各个元素的析构方法。 <br />将所有的输出刷出去。 <br />发送HTTP应答头。<br />销毁全局变量表(PG(http_globals))的变量。 <br />通过zend_deactivate函数,关闭词法分析器、语法分析器和中间代码执行器。 <br />调用每个扩展的post-RSHUTDOWN函数。只是基本每个扩展的post_deactivate_func函数指针都是NULL。 <br />关闭SAPI,通过sapi_deactivate销毁SG(sapi_headers)、SG(request_info)等的内容。 <br />关闭流的包装器、关闭流的过滤器。 <br />关闭内存管理。 <br />重新设置最大执行时间 </p>
结束
PHP结束一个进程是,会调用sapi_flush函数将最后的内容刷新出去。然后调用zend_shutdown函数关闭Zend引擎。
参考:[http://www.php-internals.com/book/](http://www.php-internals.com/book/)