说说 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

相关文章
相关标签/搜索