要約: ここで読まれている php のバージョンは PHP-7.1.0 RC3 であり、コードを読み取るためのプラットフォームは linuxZTS です。この記事には #ifdef ZTS #define CG(v) ZEND_TSRMG(compiler_globals_id) という箇所がたくさんあることがわかります。 , zend_compiler_globals *, v ) #else #define CG(v) (compi...
ここで読み込むphpのバージョンはPHP-7.1.0 RC3、コードを読み込むプラットフォームはlinux
ZTS
とさせていただきます記事内にたくさんの箇所があることを確認してください:
1 #ifdef ZTS 2 # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v) 3 #else 4 # define CG(v) (compiler_globals.v) 5 extern ZEND_API struct _zend_compiler_globals compiler_globals; 6 #endif
ここでの ZTS の概念とは何ですか? 私たちがよく使用する PHP は、CGI などの単一プロセス、単一スレッド環境で実行されます。したがって、たとえば、グローバル変数と同様に、PHP カーネルは、複数のスレッドがそれらを同時に変更および取得する場合、スレッドの安全性の問題を考慮しません。現時点では、スレッドの安全性の問題に特化したレイヤーが必要になります
ただし、コンパイル時にパラメーターを指定してコンパイルを有効にすることができます。 php のスレッドセーフ バージョン。 -enable-maintainer-zts オプション、Windows プラットフォームは --enable-zts) これが ZTS の起源です
たとえば、上記の例では、CG(V) は v を取得します。非スレッド セーフでのグローバル構造のcompiler_globals 構造の属性は、スレッド セーフでの ZEND_TSREMG メソッドを通じて取得されます。次のように zend_try_catch 関連のコードが表示されます。以下のようなおおよそのコードを参照してください:
1 zend_try { 2 ...exec_try 3 } zend_catch { 4 ...exec_catch 5 } zend_end_try();
これは何を意味しますか? まず、setjmp と longjmp を理解する必要があります。これらは、コルーチンの機能を実現するために組み合わせて使用されます。
# include
return; } else { printf("return %dn", ret); } printf("jmpn 後"); }int main(int argc, char* argv[]) { foo(); longjmp(env, 999); return 0; 出力: /* jmp 前 999 を返す jmp 後 */上記の例では、setjmp は、プログラム フラグメント 1 が主導権を渡し、次に以下のプログラム if (ret == 0) をlongjmp に遭遇するまで実行し、実行権をフラグメント 1 に戻すことと同等です。そして、jmp_buf を設定します。 999 まではフラグメント 1 が実行され続け、ret!=0 が見つかると return 999 が出力されます。 さて、このプログラムに戻りましょう:
01 { \ 02 JMP_BUF *__orig_bailout = EG(bailout); \ 03 JMP_BUF __bailout; \ 04 \ 05 EG(bailout) = &__bailout; \ 06 if (SETJMP(__bailout)==0) { 07 { 08 ...exec_try 09 } 10 } else { \ 11 EG(bailout) = __orig_bailout; 12 { 13 ...exec_catch 14 } 15 } \ 16 EG(bailout) = __orig_bailout; \ 17 }
1 まずグローバル変数にベイルアウトを保存します
2 setjmp を使用して次のプログラムを実行します3 exec_try を実行します
4 If exec_tryコードセグメントにlongjmpがあり、longjmpは非0を返します(一般的には実際には非0です)。その後、exec_catchを実行します5 最後に、グローバル変数のベイルアウトを復元します
ここで2つの疑問があるかもしれません。 exec_try? に longjmp がない場合は、 exec_try を直接実行し、 exec_catch をスキップします。これは、setjmp と longjmp を使用して try catch を実装する標準的な方法でもあります。
これら 2 つの実装は、goto キーワードが関数内でのみジャンプできるという制限を補います。これを「走り幅跳び」といいます。
つまり、PHP コードでは、実行する関数が例外をスローする可能性があります。このメソッドを使用して、実行したいプログラムを内部に配置することもできます。
上記は PHP カーネル解析 (2) の内容です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。