php內核分析之ZTS和zend-try
在學習PHP的同學對內核有沒有疑問呢?下面是本站小編精心為大家整理的php內核分析之ZTS和zend_try,希望對大家有幫助,更多內容請關注應屆畢業生網!
這裏閲讀的php版本為PHP-7.1.0 RC3,閲讀代碼的平台為linux
我們會看到文章中有很多地方是:
#ifdef ZTS
# define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v)
#else
# define CG(v) (compiler_globals.v)
extern ZEND_API struct _zend_compiler_globals compiler_globals;
#endif
這裏的ZTS是個什麼概念呢。我們經常使用的php都是運行在單進程,單線程環境,比如cgi,都是一個請求進來,就一個進程為它服務,當請求結束了,進程也就結束了。所以比如像全局變量,php內核就沒有考慮多線程同時修改獲取的時候線程安全問題。後來,php漸漸也在往單進程多線程服務器方向發展。那麼這個時候,就會需要有一個層來專門處理線程安全問題。這個就是TSRM(Thread Safe Resource Management)。
但是php默認是關閉線程安全的。在編譯的時候,你可以指定參數開啟編譯一個線程安全版本的php。(--enable-maintainer-zts 選項, Windows 平台為 --enable-zts)這個就是這裏的ZTS的由來。
比如上面的例子,CG(V) 在非線程安全下獲取的是全局結構compiler_globals結構的v屬性,在線程安全下獲取的是通過ZEND_TSREMG方法來獲取。
zend_try
我們會看到zend_try_catch相關的代碼如下:
zend_try {
_try
} zend_catch {
_catch
} zend_end_try();
把宏展開,我們可以看到大概代碼如下:
{
JMP_BUF *__orig_bailout = EG(bailout);
JMP_BUF __bailout;
EG(bailout) = &__bailout;
if (SETJMP(__bailout)==0) {
{
_try
}
} else {
EG(bailout) = __orig_bailout;
{
_catch
}
}
EG(bailout) = __orig_bailout;
}
這個是什麼意思呢,需要先理解下setjmp和longjmp,這兩個函數是linux提供的方法。他們是組合起來使用的,達到協同程序的功能
#include
#include
jmp_buf env;
void foo() {
printf("before jmpn");
int ret = setjmp(env);
if(ret == 0) {
return;
} else {
printf("return %dn", ret);
}
printf("after jmpn");
}
int main(int argc, char* argv[]) {
foo();
longjmp(env, 999);
return 0;
}
// 輸出:
/*
before jmp
return 999
after jmp
*/
上面的這個例子,setjmp的時候相當於程序片段1把主動權交出來,然後執行if(ret == 0)下面的程序,直到遇到longjmp,把執行權還給了片段1,並且設置jmp_buf為999,片段1繼續執行,發現了ret!=0,就輸出return 999。
好了,回到這個程序:
{
JMP_BUF *__orig_bailout = EG(bailout);
JMP_BUF __bailout;
EG(bailout) = &__bailout;
if (SETJMP(__bailout)==0) {
{
_try
}
} else {
EG(bailout) = __orig_bailout;
{
_catch
}
}
EG(bailout) = __orig_bailout;
}
這個程序裏面的exec_try代碼段裏面,在遇到錯誤的時候,需要返回的時候,就會包含一個longjmp函數的調用。這樣,就形成了我們平時調用al的'功能:
1 先保存全局變量裏面的bailout
2 使用setjmp來做跳轉執行下面的程序
3 執行exec_try
4 如果exec_try這個代碼段裏面有longjmp,並且longjmp返回非0(一般也確實非0),就執行exec_catch
5 最後,把全局變量裏面的bailout恢復
這裏可能會有兩個疑惑,如果exec_try裏面沒有longjmp怎麼辦,那就直接只執行了exec_try,就跳過exec_catch了。這個也是標準的用setjmp和longjmp實現try catch的寫法。
這兩個的實現彌補了goto關鍵字只能在函數內部進行跳轉的限制。這個叫做“長跳轉”。
所以在PHP代碼中,如果你執行的函數有可能拋出異常。不妨使用這個方式把你要執行的程序放在裏面。
-
PHP中超全局變量$GLOBALS和global的區別
人之所以能,是相信能。努力總是會有收穫的。下面是小編整理的PHP中超全局變量$GLOBALS和global的區別,希望對大家有用,更多消息請關注應屆畢業生網。一、超全局變量$GLOBALSPHP超全局變量有很多,如下的都屬於超全局變量(Superglobal):$GLOBALS,$_SERVER,$_GET,$_POST,$_...
-
編譯chm格式PHP手冊的方法
微軟的chm文件格式是很受我們喜愛的,因為它可以把很多HTML文件打包成一個文件,容易傳輸和分享。而且非常方便易用,支持索引、搜索等。正因為這樣,大家通常都使用chm版本的PHP手冊。php.net會定期編譯PHP手冊,提供各種版本供大家下載,包括chm格式。由於是定期編譯,所以...
-
PHP開發的安全問題
p給了開發者極大的靈活性,但是這也為安全問題帶來了潛在的隱患,下面是小編分享的PHP開發的安全問題,一起來看一下吧。安全保護一般性要點不相信表單對於一般的Javascript前台驗證,由於無法得知用户的行為,例如關閉了瀏覽器的javascript引擎,這樣通過POST惡意數據到服...
-
數據庫設計和訪問數據庫的 PHP 代碼中出現的五個常見問題
導語:您可以用很多的方式創建數據庫設計、數據庫訪問和基於數據庫的PHP業務邏輯代碼,但最終一般以錯誤告終。本文説明了數據庫設計和訪問數據庫的PHP代碼中出現的五個常見問題,以及在遇到這些問題時如何修復它們。問題1:直接使用MySQL一個常見問題是較老的PHP代碼...
相關文章
- php內核分析之sapi-module-struct
- The Best Thing That Could Ever Happen少兒雙語閲讀
- 《Dead Poets Society》觀後感:Seize the day
- php內核分析之zend-compile
- The truth about money and happiness高中英語作文
- A Letter to the University President為題目的作文
- Module9 UNIT2 Zara was happy説課稿範文
- Zend studio for eclipse中使php可以調用mysql相關函數的設置方
- The Bitter and Happiness of Study英語作文
- The relationship between theory and practice大學英語作文