摘要:如果是一個(gè),該值會(huì)作為退出狀態(tài)碼,并且不會(huì)被打印輸出。退出狀態(tài)碼應(yīng)該在范圍至,不應(yīng)使用被保留的退出狀態(tài)碼。狀態(tài)碼用于成功中止程序。所以如果是一個(gè)整數(shù),會(huì)被當(dāng)成狀態(tài)碼輸出,而不是打印,所以如果想返回給前端是不可能的。
今天有小伙伴說 exit 和 die 有一點(diǎn)差別。我說 die 不就是 exit 的別名嗎?為了證明我的觀點(diǎn),翻了翻 PHP 的源碼,在 zend_language_scanner.l 中,很容易就能發(fā)現(xiàn)這關(guān)鍵字是同一個(gè) token:
"exit" { return T_EXIT; } "die" { return T_EXIT; }
所以最終也是同一個(gè) Opcode:ZEND_EXIT。所以這兩個(gè)關(guān)鍵字沒有任何差別,這其實(shí)也沒什么好說的。
我順便提醒了小伙伴們一句:不要用 exit 輸出整數(shù)。原因也很簡單,在 PHP 官網(wǎng)的文檔里就能看到:
void?exit?([?string?$status?] )
void?exit?(?int?$status?)
如果?status?是一個(gè)字符串,在退出之前該函數(shù)會(huì)打印?status?。
如果?status?是一個(gè)?integer,該值會(huì)作為退出狀態(tài)碼,并且不會(huì)被打印輸出。 退出狀態(tài)碼應(yīng)該在范圍0至254,不應(yīng)使用被PHP保留的退出狀態(tài)碼255。 狀態(tài)碼0用于成功中止程序。
所以如果 status 是一個(gè)整數(shù),會(huì)被當(dāng)成狀態(tài)碼輸出,而不是打印,所以如果想返回給前端是不可能的。
那么這個(gè)狀態(tài)碼有什么用呢?
大家都知道 shell 腳本執(zhí)行可以返回一個(gè)狀態(tài)碼,PHP 的腳本的執(zhí)行返回的狀態(tài)碼是一樣的,可以在環(huán)境變量中被捕捉到:
Scholer: ~ $ php -r "exit(254);" Scholer: ~ $ echo $? 254
我的好奇心又被勾起來了:如果給的是不在 0 ~ 255 之間的狀態(tài)碼會(huì)怎么樣呢?經(jīng)過測試,發(fā)現(xiàn)如果是大于 255 的狀態(tài)碼,會(huì)返回 status 對 256 求余之后的結(jié)果。如果是小于 0 的,在 -1 ~ - 255 之間時(shí)返回的是 status 256 求和的結(jié)果,小于 -256 的則是絕對值和 256 求余??傊荚?0 ~ 255 之間。
接著探究下去。
exit 的實(shí)現(xiàn)在 zend_vm_def.h 中:
ZEND_VM_HANDLER(79, ZEND_EXIT, CONST|TMP|VAR|UNUSED|CV, ANY) { #if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) USE_OPLINE SAVE_OPLINE(); if (OP1_TYPE != IS_UNUSED) { zend_free_op free_op1; zval *ptr = GET_OP1_ZVAL_PTR(BP_VAR_R); if (Z_TYPE_P(ptr) == IS_LONG) { EG(exit_status) = Z_LVAL_P(ptr); } else { zend_print_variable(ptr); } FREE_OP1(); } #endif
從代碼中我們可以很明顯的看出來通過 Z_TYPE_P 來檢測狀態(tài)碼的類型,如果是 long 的話就賦值給全局變量 exit_status(EG 這個(gè)宏就是用來便捷的訪問全局變量的),如果不是,就調(diào)用 zend_print_variable 打印出來。
Z_LVAL_P 的聲明在 zend_operators.h 中:
#define Z_LVAL_P(zval_p) Z_LVAL(*zval_p) ... #define Z_LVAL(zval) (zval).value.lval
再進(jìn)一步就是大家都知道的 PHP 解釋器中的變量定義了(我這份源碼還是 PHP 5.5 的版本,不是 PHP7),在 zend.h 中:
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value */ zend_object_value obj; } zvalue_value; struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; zend_uchar type; /* active type */ zend_uchar is_ref__gc; };
所以這里 exit_status 的值到這里還是一個(gè)長整形。
那么問題就來了,為什么最終輸出的是 0 ~ 255 之間的狀態(tài)碼呢?老實(shí)說這個(gè)問題我吃的也不是很透,這需要對 Linux 環(huán)境編程足夠熟悉才行,這里只能簡單的說一下。
通過 strace 跟蹤一下執(zhí)行:
$ strace php -r "exit(258);" >& strace.log
在結(jié)果的最后兩行可以很清楚的看到:
... exit_group(258) = ? +++ exited with 2 +++
exit_group 中還是原始值,但最終會(huì)變成 2 。PHP 本身并沒有對這個(gè)值做特殊處理,但是 exit 或者 main 函數(shù)中的 return,只能使用 0 ~ 255 之間的值,其他值都會(huì)被處理??梢詫懸粋€(gè)簡單的程序測試:
int main(int argc, char const *argv[]) { return 258; }
結(jié)果:
Scholer: ~ $ ./test Scholer: ~ $ echo $? 2
詳情參見:http://www.laruence.com/2012/02/01/2503.html
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/21132.html
摘要:本節(jié)主要講解常用函數(shù)和進(jìn)程池的概念,也會(huì)涉及到守護(hù)進(jìn)程的知識。所以任何時(shí)候,建議預(yù)先創(chuàng)建好進(jìn)程,也就是使用進(jìn)程池的方式實(shí)現(xiàn)。 本節(jié)主要講解Posix常用函數(shù)和進(jìn)程池的概念,也會(huì)涉及到守護(hù)進(jìn)程的知識。本節(jié)難度較低。 Posix常用函數(shù) posix_kill 向指定pid進(jìn)程發(fā)送信號。成功時(shí)返回 TRUE , 或者在失敗時(shí)返回 FALSE 。 bool posix_kill ( int $...
摘要:多進(jìn)程消費(fèi)模型父進(jìn)程等待并控制子進(jìn)程的退出思路整理父進(jìn)程開啟后,直接獲取到子進(jìn)程的,然后存入數(shù)組,子進(jìn)程出來后直接開啟業(yè)務(wù)消費(fèi)代碼,然后退出,然后父進(jìn)程等待子進(jìn)程退出,全部退出后父進(jìn)程結(jié)束代碼請?jiān)谀J较逻\(yùn)行子進(jìn)程的數(shù)量如果是資源類型的變量, 多進(jìn)程消費(fèi)模型 父進(jìn)程等待并控制子進(jìn)程的退出 思路整理 父進(jìn)程開啟后,直接獲取到子進(jìn)程的pid,然后存入child數(shù)組,子進(jìn)程fork出來后直接開...
摘要:什么是守護(hù)進(jìn)程守護(hù)進(jìn)程是一種特殊的進(jìn)程,它的生命周期很長,它在后臺運(yùn)行并且沒有控制終端這樣可以保證守護(hù)進(jìn)程不會(huì)接收到各種來自終端的信號。比如等,都會(huì)使用守護(hù)進(jìn)程的形式運(yùn)行,確??梢砸恢闭5奶峁┓?wù)。 什么是守護(hù)進(jìn)程 守護(hù)進(jìn)程(daemon)是一種特殊的進(jìn)程,它的生命周期很長,它在后臺運(yùn)行并且沒有控制終端(這樣可以保證守護(hù)進(jìn)程不會(huì)接收到各種來自終端的信號)。比如:crontab、ssh...
摘要:調(diào)用此函數(shù),就可使當(dāng)前進(jìn)程脫離終端變成一個(gè)守護(hù)進(jìn)程,具體內(nèi)容參見。命令行程序?qū)崿F(xiàn)守護(hù)進(jìn)程化有種方法一使用這里就實(shí)現(xiàn)了守護(hù)進(jìn)程化。單獨(dú)執(zhí)行,當(dāng)按下時(shí)就會(huì)中斷程序執(zhí)行,會(huì)當(dāng)前進(jìn)程以及子進(jìn)程。 一般Server程序都是運(yùn)行在系統(tǒng)后臺,這與普通的交互式命令行程序有很大的區(qū)別。glibc里有一個(gè)函數(shù)daemon。調(diào)用此函數(shù),就可使當(dāng)前進(jìn)程脫離終端變成一個(gè)守護(hù)進(jìn)程,具體內(nèi)容參見man daemon...
摘要:本教學(xué)使用環(huán)境介紹伺服器端資料庫語言版本本機(jī)端可以透過來產(chǎn)生檔案,并丟到指定的伺服器需有存取權(quán)本端上傳到遠(yuǎn)端基本連線設(shè)定路徑設(shè)定本端的路徑遠(yuǎn)端的路徑開始上傳關(guān)閉連線遠(yuǎn)端下載到本端這塊跟上面的做法一樣開始下載注意跟擺放的位置跟上面完全相反關(guān)閉 本教學(xué)使用環(huán)境介紹伺服器端:Ubuntu 16.04資料庫:Mariadb 10.1.34(Mysql)語言版本:php 7.0本機(jī)端:MacOS...
閱讀 2212·2021-10-18 13:28
閱讀 2528·2021-10-11 10:59
閱讀 2352·2019-08-29 15:06
閱讀 1142·2019-08-26 13:54
閱讀 821·2019-08-26 13:52
閱讀 3156·2019-08-26 12:02
閱讀 3009·2019-08-26 11:44
閱讀 2521·2019-08-26 10:56