Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Allow arbitrary expressions for empty()

This change is as per RFC https://wiki.php.net/rfc/empty_isset_exprs.

The change allows passing the result of function calls and other
expressions to the empty() language construct. This is accomplished by
simply rewriting empty(expr) to !expr.

The change does not affect the suppression of errors when using empty()
on variables. empty($undefinedVar) will continue not to throw errors.
When an expression is used inside empty() on the other hand, errors will
not be suppressed. Thus empty($undefinedVar + $somethingElse) *will*
throw a notice.

The change also does not make empty() into a real function, so using
'empty' as a callback is still not possible.

In addition to the empty() changes the commit adds nicer error messages
when isset() is used on function call results or other expressions.
  • Loading branch information...
commit ec061a93c53c8cde10237741e98e992c1a05d148 1 parent 5852e5f
Nikita Popov authored April 12, 2012
3  NEWS
@@ -7,6 +7,9 @@ PHP                                                                        NEWS
7 7
   . World domination
8 8
   . Improve set_exception_handler while doing reset.(Laruence)
9 9
   . Support constant array/string dereferencing. (Laruence)
  10
+  . Add support for using empty() on the result of function calls and
  11
+    other expressions (https://wiki.php.net/rfc/empty_isset_exprs).
  12
+    (Nikita Popov)
10 13
 
11 14
 - Core:
12 15
   . Fixed bug #61681 (Malformed grammar). (Nikita Popov, Etienne, Laruence).
5  UPGRADING
@@ -28,6 +28,9 @@ PHP X.Y UPGRADE NOTES
28 28
 
29 29
 - Support constant array/string dereferencing. (Laruence)
30 30
   (https://wiki.php.net/rfc/constdereference)
  31
+- Add support for using empty() on the result of function calls and
  32
+  other expressions. Thus it is now possible to write empty(getArray()),
  33
+  for example. (https://wiki.php.net/rfc/empty_isset_exprs)
31 34
 
32 35
 ========================================
33 36
 2. Changes in SAPI modules
@@ -51,7 +54,7 @@ PHP X.Y UPGRADE NOTES
51 54
   - Implemented format character "Z": NUL-padded string
52 55
   - "a" now does not remove trailing NUL characters on unpack() anymore
53 56
   - "A" will now strip all trailing ASCII whitespace on unpack() (it used to
54  
-    remove only trailing spaces.
  57
+    remove only trailing spaces)
55 58
 
56 59
 ========================================
57 60
 5. New Functions
32  Zend/tests/empty_with_expr.phpt
... ...
@@ -0,0 +1,32 @@
  1
+--TEST--
  2
+empty() with arbitrary expressions
  3
+--FILE--
  4
+<?php
  5
+
  6
+function getEmptyArray() { return []; }
  7
+function getNonEmptyArray() { return [1, 2, 3]; }
  8
+
  9
+var_dump(empty([]));
  10
+var_dump(empty([1, 2, 3]));
  11
+
  12
+var_dump(empty(getEmptyArray()));
  13
+var_dump(empty(getNonEmptyArray()));
  14
+
  15
+var_dump(empty([] + []));
  16
+var_dump(empty([1, 2, 3] + []));
  17
+
  18
+var_dump(empty("string"));
  19
+var_dump(empty(""));
  20
+var_dump(empty(true));
  21
+var_dump(empty(false));
  22
+--EXPECT--
  23
+bool(true)
  24
+bool(false)
  25
+bool(true)
  26
+bool(false)
  27
+bool(true)
  28
+bool(false)
  29
+bool(false)
  30
+bool(true)
  31
+bool(false)
  32
+bool(true)
8  Zend/tests/isset_expr_error.phpt
... ...
@@ -0,0 +1,8 @@
  1
+--TEST--
  2
+Error message for isset(func())
  3
+--FILE--
  4
+<?php
  5
+isset(1 + 1);
  6
+?>
  7
+--EXPECTF--
  8
+Fatal error: Cannot use isset() on the result of an expression (you can use "null !== expression" instead) in %s on line %d
8  Zend/tests/isset_func_error.phpt
... ...
@@ -0,0 +1,8 @@
  1
+--TEST--
  2
+Error message for isset(func())
  3
+--FILE--
  4
+<?php
  5
+isset(abc());
  6
+?>
  7
+--EXPECTF--
  8
+Fatal error: Cannot use isset() on the result of a function call (you can use "null !== func()" instead) in %s on line %d
11  Zend/zend_compile.c
@@ -6089,7 +6089,16 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC
6089 6089
 
6090 6090
 	zend_do_end_variable_parse(variable, BP_VAR_IS, 0 TSRMLS_CC);
6091 6091
 
6092  
-	zend_check_writable_variable(variable);
  6092
+	if (zend_is_function_or_method_call(variable)) {
  6093
+		if (type == ZEND_ISEMPTY) {
  6094
+			/* empty(func()) can be transformed to !func() */
  6095
+			zend_do_unary_op(ZEND_BOOL_NOT, result, variable TSRMLS_CC);
  6096
+		} else {
  6097
+			zend_error(E_COMPILE_ERROR, "Cannot use isset() on the result of a function call (you can use \"null !== func()\" instead)");
  6098
+		}
  6099
+
  6100
+		return;
  6101
+	}
6093 6102
 
6094 6103
 	if (variable->op_type == IS_CV) {
6095 6104
 		last_op = get_next_op(CG(active_op_array) TSRMLS_CC);
10  Zend/zend_language_parser.y
@@ -1158,6 +1158,7 @@ encaps_var_offset:
1158 1158
 internal_functions_in_yacc:
1159 1159
 		T_ISSET '(' isset_variables ')' { $$ = $3; }
1160 1160
 	|	T_EMPTY '(' variable ')'	{ zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); }
  1161
+	|	T_EMPTY '(' expr_without_variable ')' { zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$3 TSRMLS_CC); }
1161 1162
 	|	T_INCLUDE expr 			{ zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }
1162 1163
 	|	T_INCLUDE_ONCE expr 	{ zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }
1163 1164
 	|	T_EVAL '(' expr ')' 	{ zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }
@@ -1166,8 +1167,13 @@ internal_functions_in_yacc:
1166 1167
 ;
1167 1168
 
1168 1169
 isset_variables:
1169  
-		variable 				{ zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$1 TSRMLS_CC); }
1170  
-	|	isset_variables ',' { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } variable { znode tmp; zend_do_isset_or_isempty(ZEND_ISSET, &tmp, &$4 TSRMLS_CC); zend_do_boolean_and_end(&$$, &$1, &tmp, &$2 TSRMLS_CC); }
  1170
+		isset_variable			{ $$ = $1; }
  1171
+	|	isset_variables ',' { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } isset_variable { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
  1172
+;
  1173
+
  1174
+isset_variable:
  1175
+		variable				{ zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$1 TSRMLS_CC); }
  1176
+	|	expr_without_variable	{ zend_error(E_COMPILE_ERROR, "Cannot use isset() on the result of an expression (you can use \"null !== expression\" instead)"); }
1171 1177
 ;
1172 1178
 
1173 1179
 class_constant:

0 notes on commit ec061a9

Please sign in to comment.
Something went wrong with that request. Please try again.