bool empty ( mixed $var )判断变量是否为空。
bool isset ( mixed $var [ , mixed $... ] )判断变量是否被设置且不为NULL。
$result = empty(0); // true$result = empty(null); // true$result = empty(false); // true$result = empty(array()); // true$result = empty("0"); // true$result = empty(1); // false$result = empty(callback function); // 报错$a = null;$result = isset($a); // false;$a = 1;$result = isset($a); // true;$a = 1;$b = 2;$c = 3;$result = isset($a, $b, $c); // true$a = 1;$b = null;$c = 3;$result = isset($a, $b, $c); // false找到函数的定义位置

在第一个阶段,即Scanning阶段,程序会扫描zend_language_scanner.l文件将代码文件转换成语言片段。对于isset和empty函数来说,在zend_language_scanner.l文件中搜索empty和isset可以得到函数在此文件中的宏定义如下:
<ST_IN_SCRIPTING>"isset" {return T_ISSET;}<ST_IN_SCRIPTING>"empty" {return T_EMPTY;}接下来就到了Parsing阶段,这个阶段,程序将T_ISSET和T_EMPTY等Tokens转换成有意义的表达式,此时会做语法分析,Tokens的yacc保存在zend_language_parser.y文件中,可以找到T_ISSET和T_EMPTY的定义internal_functions_in_yacc:T_ISSET "(" isset_variables ")" { $$ = $3; }| T_EMPTY "(" variable ")" { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); }| T_INCLUDE expr { zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }| T_INCLUDE_ONCE expr { zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }| T_EVAL "(" expr ")" { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }| T_REQUIRE expr { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }| T_REQUIRE_ONCE expr { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); };isset和empty函数最终都执行了zend_do_isset_or_isempty函数,继续查找switch (Z_TYPE_P(op)) {case IS_NULL:result = 0;break;case IS_LONG:case IS_BOOL:case IS_RESOURCE:// empty参数为整数时非0的话就为falseresult = (Z_LVAL_P(op)?1:0);break;case IS_DOUBLE:result = (Z_DVAL_P(op) ? 1 : 0);break;case IS_STRING:if (Z_STRLEN_P(op) == 0|| (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=="0")) {// empty("0") == trueresult = 0;} else {result = 1;}break;case IS_ARRAY:// empty(array) 是根据数组的数量来判断result = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);break;case IS_OBJECT:if(IS_ZEND_STD_OBJECT(*op)) {TSRMLS_FETCH();if (Z_OBJ_HT_P(op)->cast_object) {zval tmp;if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_BOOL TSRMLS_CC) == SUCCESS) {result = Z_LVAL(tmp);break;}} else if (Z_OBJ_HT_P(op)->get) {zval *tmp = Z_OBJ_HT_P(op)->get(op TSRMLS_CC);if(Z_TYPE_P(tmp) != IS_OBJECT) {/* for safety - avoid loop */convert_to_boolean(tmp);result = Z_LVAL_P(tmp);zval_ptr_dtor(&tmp);break;}}}result = 1;break;default:result = 0;break;}这段代码比较直观,函数没有对检测值做任何的转换,通过这段代码来进一步分析示例中的empty函数做分析:if (isset && Z_TYPE_PP(value) != IS_NULL) {ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 1);} else {ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 0);}只要value被设置了且不为NULL,isset函数就返回true。