Permalink
Browse files

Merge branch 'pull-request/54'

* pull-request/54:
  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...
2 parents 3bd0a52 + ec061a9 commit b187c35f236edd7370d63f02c26d5272997830ee @smalyshev smalyshev committed May 24, 2012
View
3 NEWS
@@ -7,6 +7,9 @@ PHP NEWS
. World domination
. Improve set_exception_handler while doing reset.(Laruence)
. Support constant array/string dereferencing. (Laruence)
+ . Add support for using empty() on the result of function calls and
+ other expressions (https://wiki.php.net/rfc/empty_isset_exprs).
+ (Nikita Popov)
- Core:
. Fixed bug #61681 (Malformed grammar). (Nikita Popov, Etienne, Laruence).
View
5 UPGRADING
@@ -28,6 +28,9 @@ PHP X.Y UPGRADE NOTES
- Support constant array/string dereferencing. (Laruence)
(https://wiki.php.net/rfc/constdereference)
+- Add support for using empty() on the result of function calls and
+ other expressions. Thus it is now possible to write empty(getArray()),
+ for example. (https://wiki.php.net/rfc/empty_isset_exprs)
========================================
2. Changes in SAPI modules
@@ -51,7 +54,7 @@ PHP X.Y UPGRADE NOTES
- Implemented format character "Z": NUL-padded string
- "a" now does not remove trailing NUL characters on unpack() anymore
- "A" will now strip all trailing ASCII whitespace on unpack() (it used to
- remove only trailing spaces.
+ remove only trailing spaces).
- MessageFormatter::format() and related functions now accepted named arguments
and mixed numeric/named arguments in ICU 4.8+.
- MessageFormatter::format() and related functions now don't error out when
View
32 Zend/tests/empty_with_expr.phpt
@@ -0,0 +1,32 @@
+--TEST--
+empty() with arbitrary expressions
+--FILE--
+<?php
+
+function getEmptyArray() { return []; }
+function getNonEmptyArray() { return [1, 2, 3]; }
+
+var_dump(empty([]));
+var_dump(empty([1, 2, 3]));
+
+var_dump(empty(getEmptyArray()));
+var_dump(empty(getNonEmptyArray()));
+
+var_dump(empty([] + []));
+var_dump(empty([1, 2, 3] + []));
+
+var_dump(empty("string"));
+var_dump(empty(""));
+var_dump(empty(true));
+var_dump(empty(false));
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
View
8 Zend/tests/isset_expr_error.phpt
@@ -0,0 +1,8 @@
+--TEST--
+Error message for isset(func())
+--FILE--
+<?php
+isset(1 + 1);
+?>
+--EXPECTF--
+Fatal error: Cannot use isset() on the result of an expression (you can use "null !== expression" instead) in %s on line %d
View
8 Zend/tests/isset_func_error.phpt
@@ -0,0 +1,8 @@
+--TEST--
+Error message for isset(func())
+--FILE--
+<?php
+isset(abc());
+?>
+--EXPECTF--
+Fatal error: Cannot use isset() on the result of a function call (you can use "null !== func()" instead) in %s on line %d
View
11 Zend/zend_compile.c
@@ -6090,7 +6090,16 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC
zend_do_end_variable_parse(variable, BP_VAR_IS, 0 TSRMLS_CC);
- zend_check_writable_variable(variable);
+ if (zend_is_function_or_method_call(variable)) {
+ if (type == ZEND_ISEMPTY) {
+ /* empty(func()) can be transformed to !func() */
+ zend_do_unary_op(ZEND_BOOL_NOT, result, variable TSRMLS_CC);
+ } else {
+ zend_error(E_COMPILE_ERROR, "Cannot use isset() on the result of a function call (you can use \"null !== func()\" instead)");
+ }
+
+ return;
+ }
if (variable->op_type == IS_CV) {
last_op = get_next_op(CG(active_op_array) TSRMLS_CC);
View
10 Zend/zend_language_parser.y
@@ -1158,6 +1158,7 @@ encaps_var_offset:
internal_functions_in_yacc:
T_ISSET '(' isset_variables ')' { $$ = $3; }
| T_EMPTY '(' variable ')' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); }
+ | T_EMPTY '(' expr_without_variable ')' { zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$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); }
@@ -1166,8 +1167,13 @@ internal_functions_in_yacc:
;
isset_variables:
- variable { zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$1 TSRMLS_CC); }
- | 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); }
+ isset_variable { $$ = $1; }
+ | isset_variables ',' { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } isset_variable { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
+;
+
+isset_variable:
+ variable { zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$1 TSRMLS_CC); }
+ | expr_without_variable { zend_error(E_COMPILE_ERROR, "Cannot use isset() on the result of an expression (you can use \"null !== expression\" instead)"); }
;
class_constant:

0 comments on commit b187c35

Please sign in to comment.