說說 PHP 的 die 和 exit

博客連接:http://0x1.im/blog/php/php-exit-die.htmlphp

今天有小夥伴說 exit 和 die 有一點差異。我說 die 不就是 exit 的別名嗎?爲了證實個人觀點,翻了翻 PHP 的源碼,在 zend_language_scanner.l 中,很容易就能發現這關鍵字是同一個 token:html

<ST_IN_SCRIPTING>"exit" {
	return T_EXIT;
}

<ST_IN_SCRIPTING>"die" {
	return T_EXIT;
}

因此最終也是同一個 Opcode:ZEND_EXIT。因此這兩個關鍵字沒有任何差異,這其實也沒什麼好說的。前端

我順便提醒了小夥伴們一句:不要用 exit 輸出整數。緣由也很簡單,在 PHP 官網的文檔裏就能看到:shell

void exit ([ string $status ] )編程

void exit ( int $status )函數

若是 status 是一個字符串,在退出以前該函數會打印 status 。測試

若是 status 是一個 integer,該值會做爲退出狀態碼,而且不會被打印輸出。 退出狀態碼應該在範圍0至254,不該使用被PHP保留的退出狀態碼255。 狀態碼0用於成功停止程序。ui

因此若是 status 是一個整數,會被當成狀態碼輸出,而不是打印,因此若是想返回給前端是不可能的。.net

那麼這個狀態碼有什麼用呢?code

你們都知道 shell 腳本執行能夠返回一個狀態碼,PHP 的腳本的執行返回的狀態碼是同樣的,能夠在環境變量中被捕捉到:

Scholer: ~ $ php -r 'exit(254);'

Scholer: ~ $ echo $?
254

個人好奇心又被勾起來了:若是給的是不在 0 ~ 255 之間的狀態碼會怎麼樣呢?通過測試,發現若是是大於 255 的狀態碼,會返回 status 對 256 求於以後的結果。若是是小於 0 的,在 -1 ~ - 255 之間時返回的是 status 256 求和的結果,小於 -256 的則是絕對值和 256 求餘。總之都在 0 ~ 255 之間。

接着探究下去。

exit 的實如今 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 來檢測狀態碼的類型,若是是 long 的話就賦值給全局變量 exit_status(EG 這個宏就是用來便捷的訪問全局變量的),若是不是,就調用 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

再進一步就是你們都知道的 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 的值到這裏仍是一個長整形。

那麼問題就來了,爲何最終輸出的是 0 ~ 255 之間的狀態碼呢?老實說這個問題我吃的也不是很透,這須要對 Linux 環境編程足夠熟悉才行,這裏只能簡單的說一下。

經過 strace 跟蹤一下執行:

$ strace php -r 'exit(258);' >& strace.log

在結果的最後兩行能夠很清楚的看到:

...
exit_group(258)                         = ?
+++ exited with 2 +++

exit_group 中仍是原始值,但最終會變成 2 。PHP 自己並無對這個值作特殊處理,可是 exit 或者 main 函數中的 return,只能使用 0 ~ 255 之間的值,其餘值都會被處理。能夠寫一個簡單的程序測試:

int main(int argc, char const *argv[])
{
    return 258;
}

結果:

Scholer: ~ $ ./test

Scholer: ~ $ echo $?
2

詳情參見:http://www.laruence.com/2012/02/01/2503.html

相關文章
相關標籤/搜索