ホームページ  >  記事  >  php教程  >  PHPカーネル解析(2)

PHPカーネル解析(2)

黄舟
黄舟オリジナル
2016-12-19 11:06:111104ブラウズ

要約: ここで読まれている 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 を理解する必要があります。これらは、コルーチンの機能を実現するために組み合わせて使用​​されます。 ade979de5fc0e1ca0540f360a64c230b

# include 141642a285ad26cf7e55efeead7f8373

jmp_buf env;

void foo() {

printf("before jmpn");

int ret = setjmp(env); if(ret == 0) {

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    }

このプログラムの exec_try コード セグメントには、エラーが発生して返す必要がある場合に、longjmp 関数への呼び出しが含まれています。このようにして、try...catch...finnal を呼び出す通常の関数が形成されます:

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) に注目してください。




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