PHP は、シンプルかつ強力な言語として、Web に適した多くの言語機能を提供できます。 Wang Shuai は実践から始めて、弱く型付けされた変数の原理を探求した後、PHP カーネルのいくつかの共通部分を明確にします。この問題は、SAPI を深く理解するためのものです。
SAPIはServer Application Programming Interfaceの略称です。 PHP は、アプリケーションと PHP カーネル間のデータ対話のために SAPI を介して一連のインターフェイスを提供します。
簡単に言うと、関数の入出力と同じように、Linux コマンド ラインを介して PHP コードを実行します。本質は、Zend エンジンの実行後に Linux シェルが PHP の SAPI を介して一連のパラメーターを渡すことです。 、シェルによって表示されるプロセスに戻ります。同様に、PHP は Apache 経由で呼び出され、Zend エンジンの実行後にデータが Web サーバー経由で SAPI に渡され、Apache によってページに表示されます。
図 1. PHP アーキテクチャ図
PHP は、Apache、apache2filter、apache2handler、caudium、cgi、cgi-fcgi、cli、cli-server、continuity、embed、isapi、litespeed、milter、nsapi など、さまざまな形式のインターフェイスを提供します、phttpd pi3web、roxen、thttpd、tux、webjames。ただし、一般的に使用される形式は、CLI/CGI (コマンド ライン)、Multiprocess (マルチプロセス)、Multithreaded (マルチスレッド)、FastCGI、および Embedded (組み込み) の 5 つだけです。
PHP は、現在の SAPI インターフェイス タイプを表示する関数を提供します:
string php_sapi_name ( void )
どの SAPI が使用されるかに関係なく、PHP がスクリプトを実行する前後には、一連のイベントが含まれます: モジュールの初期化 (MINT)およびシャットダウン (MSHUTDOWN)、リクエストの初期化 (RINT) およびシャットダウン (RSHUTDOWN)。 最初のフェーズは PHP モジュール初期化フェーズ (MINT) で、拡張内部変数の初期化、リソースの割り当て、リソース プロセッサの登録が可能です。このプロセスは、PHP インスタンスのライフ サイクル全体で 1 回だけ実行されます。
PHPモジュールとは何ですか?上記の PHP アーキテクチャ図を通じて、PHP の get_loaded_extensions 関数を使用して、コンパイルおよびロードされたすべてのモジュール/拡張機能を表示できます。これは、CLI モードの php -m と同等です。
PHP の Memcached 拡張ソース コードを例に挙げます:
PHP_MINIT_FUNCTION(memcached) { zend_class_entry ce; memcpy(&memcached_object_handlers,zend_get_std_object_handlers(), sizeof(zend_object_handlers)); memcached_object_handlers.clone_obj = NULL; /* 执行了一些类似的初始化操作 */ return SUCCESS; }
2 番目のフェーズはリクエスト初期化フェーズ (RINT) で、モジュールが初期化されてアクティブ化された後、PHP 実行環境が作成され、RINT 関数がすべてのユーザーによって登録されます。モジュールは、特定の環境変数の設定、リソースの割り当て、または監査などの他のタスクを実行するための拡張リクエスト初期化関数も同時に呼び出されます。
PHP_RINIT_FUNCTION(memcached) { /* 执行一些关于请求的初始化 */ return SUCCESS; }
3 番目の段階では、リクエストの処理が完了した後、リサイクルのために PHP_RSHUTDOWN_FUNCTION が呼び出され、最終的なクリーンアップ作業を実行する各拡張機能のリクエスト終了関数です。 Zend エンジンはクリーンアップ プロセス、ガベージ コレクションを実行し、以前のリクエストで使用されたすべての変数の設定を解除します。リクエストは、スクリプトを実行するか、die() 関数または exit() 関数を呼び出すことによって完了できます。PHP ライフサイクルが終了すると、PHP_MSHUTDOWN_FUNCTION がモジュールをリサイクルします。これは、各拡張モジュールのシャットダウンです。自身のカーネル サブシステムをシャットダウンします。
PHP_MSHUTDOWN_FUNCTION(memcached) { /* 执行关于模块的销毁工作 */ UNREGISTER_INI_ENTRIES(); return SUCCESS; }
共通の動作モード
CLI と CGI はどちらもシングルプロセス モードに属し、PHP のライフサイクルは 1 つのリクエストで完了します。つまり、PHP スクリプトが実行されるたびに、2 番目の部分で説明した 4 つの INT イベントと Shutdown イベントが実行されます。
図 2. CGI/CLI ライフサイクル
2. マルチプロセス モード (マルチプロセス)
マルチプロセス モードでは、PHP を Web サーバーに組み込むことができ、PHP は Apache の下でプリフォーク MPM モードと APXS モジュールにコンパイルできます。が開始されると、多くの子プロセスがフォークされ、各子プロセスは独自の独立したプロセス アドレス空間を持ちます。
図 3. マルチプロセス モードのライフ サイクル
子プロセスでは、PHP のライフ サイクルは、MINT を呼び出して複数のリクエスト (RINT/RSHUTDOWN) を開始および実行します。Apache がシャットダウンされるまで呼び出されません。または、プロセスが終了し、リサイクルフェーズに進みます。
図 4. マルチプロセスのライフサイクル
マルチプロセス モデルでは、各サブプロセスはコードとデータを共有せずに独立して実行されるため、1 つのサブプロセスの終了、終了、再生成は影響を受けません。他のサブプロセスの安定性。
3. マルチスレッドモード (マルチスレッド)
Apache2 の Worker MPM は、1 つのプロセスの下に複数のスレッドを作成し、同じプロセスのアドレス空間で実行するマルチスレッド モデルを採用しています。
図 5. マルチスレッドのライフサイクル
4. FastCGI モード
私たちが使用する Nginx+PHP-FPM では、FastCGI モードを使用して、CGI の常駐プロセス タイプを使用できます。実行後に複数のプロセスをフォークします。時間を費やすことなく、子プロセスを動的にフォークします。リクエストごとに MINT/MSHUTDOWN を呼び出す必要はありません。 PHP は、PHP-FPM を通じて FastCGI のプロセス プールを管理およびスケジュールします。 Nginx と PHP-FPM は、ローカル TCP ソケットと Unix ソケットを介して通信します。
図 6. FastCGI モードのライフサイクル
PHP-FPM进程管理器自身初始化,启动多个CGI解释器进程等待来自Nginx的请求。当客户端请求达到PHP-FPM,管理器选择到一个CGI进程进行处理,Nginx将CGI环境变量和标准输入发送到一个PHP-CIG子进程。PHP-CGI子进程处理完成后,将标准输出和错误信息返回给Nginx,当PHP-CGI子进程关闭连接时,请求处理完成。PHP-CGI子进程等待着下一个连接。
可以想象CGI的系统开销有多大。每一个Web 请求PHP都必须重新解析php.ini、载入全部扩展并始化全部数据结构。使用FastCGI,所有这些都只在进程启动时发生一次。另外,对于数据库和Memcache的持续连接可以工作。
5. 内嵌模式(Embedded)
Embed SAPI是一种特殊的SAPI,允许在C/C++语言中调用PHP提供的函数。这种SAPI和CLI模式一样,按照Module Init => Request Init => Request => Request Shutdown => Module Shutdown的模式运行。
Embed SAPI可以调用PHP丰富的类库,也可以实现高级玩法,比如可以查看PHP的OPCODE(PHP执行的中间码,Zend引擎的指令,由PHP代码生成)。
详细请见: http://www.laruence.com/2008/09/23/539.html
我们以CGI为例,看一下SAPI的运行机制。
static sapi_module_struct cgi_sapi_module = { "cgi-fcgi", /* 输出给php_info()使用 */ "CGI/FastCGI", /* pretty name */ php_cgi_startup, /* startup 当SAPI初始化时,首先会调用该函数 */ php_module_shutdown_wrapper, /* shutdown 关闭函数包装器,它用来释放所有的SAPI的数据结构、内存等,调用php_module_shutdown */ sapi_cgi_activate, /* activate 此函数会在每个请求开始时调用,它会做初始化,资源分配 */ sapi_cgi_deactivate, /* deactivate 此函数会在每个请求结束时调用,它用来确保所有的数据都得到释放 */ sapi_cgi_ub_write, /* unbuffered write 不缓存的写操作(unbuffered write),它是用来向SAPI外部输出数据 */ sapi_cgi_flush, /* flush 刷新输出,在CLI模式下通过使用C语言的库函数fflush实现*/ NULL, /* get uid */ sapi_cgi_getenv, /* getenv 根据name查找环境变量 */ php_error, /* error handler 注册错误处理函数 */ NULL, /* header handler PHP调用header()时候被调用 */ sapi_cgi_send_headers, /* send headers handler 发送头部信息*/ NULL, /* send header handler 发送一个单独的头部信息 */ sapi_cgi_read_post, /* read POST data 当请求的方法是POST时,程序获取POST数据,写入$_POST数组 */ sapi_cgi_read_cookies, /* read Cookies 获取Cookie值 */ sapi_cgi_register_variables, /* register server variables 给$_SERVER添加环境变量 */ sapi_cgi_log_message, /* Log message 输出错误信息 */ NULL, /* Get request time */ NULL, /* Child terminate */ STANDARD_SAPI_MODULE_PROPERTIES };
由上面代码可见,PHP的SAPI像是面向对象中基类,SAPI.h和SAPI.c包含的函数是抽象基类的声明和定义,各个服务器用的SAPI模式,则是继承了这个基类,并重新定义基类方法的子类。
PHP的SAPI是Zend引擎提供的一组标准交互接口,通过注册初始化、析构、输入、输出等接口,我们可以将应用程序运行在Zend引擎上,也可以把PHP嵌入到类似Apache的Web Server中。PHP常见的SAPI模式有五种,CGI/CLI模式、多进程模式、多线程模式、FastCGI模式和内嵌模式。
了解PHP的SAPI机制意义重大,帮助我们理解PHP的生命周期,并了解如何更好的通过C/C++为PHP编写扩展,并在生命周期中找到提高系统性能的方式。
相关推荐:
以上がPHP カーネル SAPI 探索サンプルの共有の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。