Deprecate nesting ternary operators without explicit parentheses.
RFC: https://wiki.php.net/rfc/ternary_associativity
. "fn" is now a reserved keyword. In particular it can no longer be used as a
function or class name. It can still be used as a method or class constant
name.
+ . Nesting ternary operators without explicit parentheses is deprecated:
+
+ // Code like
+ $a ? $b : $c ? $d : $e
+ // should be replaced by (current interpretation)
+ ($a ? $b : $c) ? $d : $e
+ // or (likely intended interpretation)
+ $a ? $b : ($c ? $d : $e)
+
+ RFC: https://wiki.php.net/rfc/ternary_associativity
- Curl:
. Attempting to serialize a CURLFile class will now generate an exception.
Bug #72944 (Null pointer deref in zval_delref_p).
--FILE--
<?php
-"a"== e & $A = $A? 0 : 0 ?:0;
+("a"== e & $A = $A? 0 : 0) ?:0;
echo "OK\n";
?>
--EXPECTF--
--- /dev/null
+--TEST--
+Using ternary associativity is deprecated
+--FILE--
+<?php
+
+1 ? 2 : 3 ? 4 : 5; // deprecated
+(1 ? 2 : 3) ? 4 : 5; // ok
+1 ? 2 : (3 ? 4 : 5); // ok
+
+// While the associativity of ?: is also incorrect, it will not cause a
+// functional difference, only some unnecessary checks.
+1 ?: 2 ?: 3; // ok
+(1 ?: 2) ?: 3; // ok
+1 ?: (2 ?: 3); // ok
+
+1 ?: 2 ? 3 : 4; // deprecated
+(1 ?: 2) ? 3 : 4; // ok
+1 ?: (2 ? 3 : 4); // ok
+
+1 ? 2 : 3 ?: 4; // deprecated
+(1 ? 2 : 3) ?: 4; // ok
+1 ? 2 : (3 ?: 4); // ok
+
+?>
+--EXPECTF--
+Deprecated: Unparenthesized `a ? b : c ? d : e` is deprecated. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)` in %s on line 3
+
+Deprecated: Unparenthesized `a ?: b ? c : d` is deprecated. Use either `(a ?: b) ? c : d` or `a ?: (b ? c : d)` in %s on line 13
+
+Deprecated: Unparenthesized `a ? b : c ?: d` is deprecated. Use either `(a ? b : c) ?: d` or `a ? b : (c ?: d)` in %s on line 17
zend_op *opline_qm_assign2;
uint32_t opnum_jmpz, opnum_jmp;
+ if (cond_ast->kind == ZEND_AST_CONDITIONAL
+ && cond_ast->attr != ZEND_PARENTHESIZED_CONDITIONAL) {
+ if (cond_ast->child[1]) {
+ if (true_ast) {
+ zend_error(E_DEPRECATED,
+ "Unparenthesized `a ? b : c ? d : e` is deprecated. "
+ "Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)`");
+ } else {
+ zend_error(E_DEPRECATED,
+ "Unparenthesized `a ? b : c ?: d` is deprecated. "
+ "Use either `(a ? b : c) ?: d` or `a ? b : (c ?: d)`");
+ }
+ } else {
+ if (true_ast) {
+ zend_error(E_DEPRECATED,
+ "Unparenthesized `a ?: b ? c : d` is deprecated. "
+ "Use either `(a ?: b) ? c : d` or `a ?: (b ? c : d)`");
+ } else {
+ /* This case is harmless: (a ?: b) ?: c always produces the same result
+ * as a ?: (b ?: c). */
+ }
+ }
+ }
+
if (!true_ast) {
zend_compile_shorthand_conditional(result, ast);
return;
#define ZEND_ARRAY_NOT_PACKED (1<<1)
#define ZEND_ARRAY_SIZE_SHIFT 2
+/* Attribute for ternary inside parentheses */
+#define ZEND_PARENTHESIZED_CONDITIONAL 1
+
/* For "use" AST nodes and the seen symbol table */
#define ZEND_SYMBOL_CLASS (1<<0)
#define ZEND_SYMBOL_FUNCTION (1<<1)
{ $$ = zend_ast_create_binary_op(ZEND_SPACESHIP, $1, $3); }
| expr T_INSTANCEOF class_name_reference
{ $$ = zend_ast_create(ZEND_AST_INSTANCEOF, $1, $3); }
- | '(' expr ')' { $$ = $2; }
+ | '(' expr ')' {
+ $$ = $2;
+ if ($$->kind == ZEND_AST_CONDITIONAL) $$->attr = ZEND_PARENTHESIZED_CONDITIONAL;
+ }
| new_expr { $$ = $1; }
| expr '?' expr ':' expr
{ $$ = zend_ast_create(ZEND_AST_CONDITIONAL, $1, $3, $5); }