diff --git a/UPGRADING b/UPGRADING index ae8e276119887..3820beae58cb8 100644 --- a/UPGRADING +++ b/UPGRADING @@ -427,6 +427,8 @@ PHP 8.0 UPGRADE NOTES RFC: https://wiki.php.net/rfc/variable_syntax_tweaks . Added Stringable. RFC: https://wiki.php.net/rfc/stringable + . Added type casting in array destructuring expressions. + RFC: https://wiki.php.net/rfc/typecast_array_desctructuring - Date: . Added DateTime::createFromInterface() and diff --git a/Zend/tests/list/list_casting_001.phpt b/Zend/tests/list/list_casting_001.phpt new file mode 100644 index 0000000000000..e29bb697a11ba --- /dev/null +++ b/Zend/tests/list/list_casting_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +"Cast during unpacking - general" list() +--FILE-- + +--EXPECT-- +string(1) "1" +bool(true) +float(3) +int(4) +string(1) "1" +bool(true) +float(3) +int(4) diff --git a/Zend/tests/list/list_casting_002.phpt b/Zend/tests/list/list_casting_002.phpt new file mode 100644 index 0000000000000..97255e5511b8e --- /dev/null +++ b/Zend/tests/list/list_casting_002.phpt @@ -0,0 +1,21 @@ +--TEST-- +"Cast during unpacking - non existing values" list() +--FILE-- + +--EXPECT-- +string(0) "" +bool(false) +float(0) +NULL +string(0) "" +bool(false) +float(0) +NULL diff --git a/Zend/tests/list/list_casting_003.phpt b/Zend/tests/list/list_casting_003.phpt new file mode 100644 index 0000000000000..e47e22183d384 --- /dev/null +++ b/Zend/tests/list/list_casting_003.phpt @@ -0,0 +1,21 @@ +--TEST-- +"Cast during unpacking - nested unpacking" list() +--FILE-- + +--EXPECT-- +string(1) "1" +bool(true) +float(3) +int(4) +string(1) "1" +bool(true) +float(3) +int(4) diff --git a/Zend/tests/list/list_casting_004.phpt b/Zend/tests/list/list_casting_004.phpt new file mode 100644 index 0000000000000..63839cae4d179 --- /dev/null +++ b/Zend/tests/list/list_casting_004.phpt @@ -0,0 +1,21 @@ +--TEST-- +"Cast during unpacking - associative unpacking" list() +--FILE-- + 1, 'b' => 2, 'c' => 3, 'd' => 4]; + +list('a' => (string) $a, 'b' => (bool) $b, 'c' => (float) $c, 'd' => $d) = $arr; +var_dump($a, $b, $c, $d); + +['a' => (string) $a, 'b' => (bool) $b, 'c' => (float) $c, 'd' => $d] = $arr; +var_dump($a, $b, $c, $d); +?> +--EXPECT-- +string(1) "1" +bool(true) +float(3) +int(4) +string(1) "1" +bool(true) +float(3) +int(4) diff --git a/Zend/tests/list/list_casting_005.phpt b/Zend/tests/list/list_casting_005.phpt new file mode 100644 index 0000000000000..fdc718cb892f4 --- /dev/null +++ b/Zend/tests/list/list_casting_005.phpt @@ -0,0 +1,21 @@ +--TEST-- +"Cast during unpacking - nested associative unpacking" list() +--FILE-- + 1, 'b' => ['b1' => 2, 'b2' => 3], 'c' => 4]; + +list('a' => (string) $a, 'b' => list('b1' => (bool) $b, 'b2' => (float) $c), 'c' => $d) = $arr; +var_dump($a, $b, $c, $d); + +['a' => (string) $a, 'b' => ['b1' => (bool) $b, 'b2' => (float) $c], 'c' => $d] = $arr; +var_dump($a, $b, $c, $d); +?> +--EXPECT-- +string(1) "1" +bool(true) +float(3) +int(4) +string(1) "1" +bool(true) +float(3) +int(4) diff --git a/Zend/tests/list/list_casting_006.phpt b/Zend/tests/list/list_casting_006.phpt new file mode 100644 index 0000000000000..a47d32880f2de --- /dev/null +++ b/Zend/tests/list/list_casting_006.phpt @@ -0,0 +1,27 @@ +--TEST-- +"Cast during unpacking - foreach loop" list() +--FILE-- + +--EXPECT-- +string(1) "1" +bool(true) +int(3) +string(1) "4" +bool(true) +int(6) +string(1) "1" +bool(true) +int(3) +string(1) "4" +bool(true) +int(6) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2050e3ba71151..c6824cc3f1c8f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2809,6 +2809,25 @@ static zend_bool zend_propagate_list_refs(zend_ast *ast) { /* {{{ */ } /* }}} */ +void zend_compile_cast(znode *result, zend_ast *ast) /* {{{ */ +{ + zend_ast *expr_ast = ast->child[0]; + znode expr_node; + zend_op *opline; + + zend_compile_expr(&expr_node, expr_ast); + + if (ast->attr == _IS_BOOL) { + opline = zend_emit_op_tmp(result, ZEND_BOOL, &expr_node, NULL); + } else if (ast->attr == IS_NULL) { + zend_error(E_COMPILE_ERROR, "The (unset) cast is no longer supported"); + } else { + opline = zend_emit_op_tmp(result, ZEND_CAST, &expr_node, NULL); + opline->extended_value = ast->attr; + } +} +/* }}} */ + static void zend_compile_list_assign( znode *result, zend_ast *ast, znode *expr_node, zend_bool old_style) /* {{{ */ { @@ -2824,6 +2843,7 @@ static void zend_compile_list_assign( for (i = 0; i < list->children; ++i) { zend_ast *elem_ast = list->child[i]; + zend_ast *cast_ast = NULL; zend_ast *var_ast, *key_ast; znode fetch_result, dim_node; zend_op *opline; @@ -2867,6 +2887,11 @@ static void zend_compile_list_assign( Z_TRY_ADDREF(expr_node->u.constant); } + if (var_ast->kind == ZEND_AST_CAST) { + cast_ast = var_ast; + var_ast = var_ast->child[0]; + } + zend_verify_list_assign_target(var_ast, old_style); opline = zend_emit_op(&fetch_result, @@ -2886,6 +2911,11 @@ static void zend_compile_list_assign( } else { zend_emit_assign_znode(var_ast, &fetch_result); } + + if (cast_ast) { + zend_compile_cast(&fetch_result, cast_ast); + zend_emit_assign_znode(var_ast, &fetch_result); + } } if (has_elems == 0) { @@ -7694,25 +7724,6 @@ void zend_compile_pre_incdec(znode *result, zend_ast *ast) /* {{{ */ } /* }}} */ -void zend_compile_cast(znode *result, zend_ast *ast) /* {{{ */ -{ - zend_ast *expr_ast = ast->child[0]; - znode expr_node; - zend_op *opline; - - zend_compile_expr(&expr_node, expr_ast); - - if (ast->attr == _IS_BOOL) { - opline = zend_emit_op_tmp(result, ZEND_BOOL, &expr_node, NULL); - } else if (ast->attr == IS_NULL) { - zend_error(E_COMPILE_ERROR, "The (unset) cast is no longer supported"); - } else { - opline = zend_emit_op_tmp(result, ZEND_CAST, &expr_node, NULL); - opline->extended_value = ast->attr; - } -} -/* }}} */ - static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast) /* {{{ */ { zend_ast *cond_ast = ast->child[0];