mirror of
https://github.com/php/php-src.git
synced 2026-04-24 16:38:25 +02:00
Support references in foreach()
Syntax: foreach ($arr as &$val) foreach ($arr as $key => &$val)
This commit is contained in:
+20
-2
@@ -2973,15 +2973,17 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack
|
||||
opline->result.op_type = IS_TMP_VAR;
|
||||
opline->result.u.var = get_temporary_variable(CG(active_op_array));
|
||||
opline->op1 = *open_brackets_token;
|
||||
opline->extended_value = 0;
|
||||
SET_UNUSED(opline->op2);
|
||||
*as_token = opline->result;
|
||||
}
|
||||
|
||||
|
||||
void zend_do_foreach_cont(znode *value, znode *key, znode *as_token TSRMLS_DC)
|
||||
void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC)
|
||||
{
|
||||
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
znode result_value, result_key, dummy;
|
||||
zend_bool assign_by_ref=0;
|
||||
|
||||
if (key->op_type != IS_UNUSED) {
|
||||
znode *tmp;
|
||||
@@ -2992,6 +2994,18 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token TSRMLS_DC)
|
||||
value = tmp;
|
||||
}
|
||||
|
||||
if (key->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE) {
|
||||
zend_error(E_COMPILE_ERROR, "Key element cannot be a reference");
|
||||
}
|
||||
|
||||
if (value->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE) {
|
||||
assign_by_ref = 1;
|
||||
if (!CG(active_op_array)->opcodes[foreach_token->u.opline_num-1].extended_value) {
|
||||
zend_error(E_COMPILE_ERROR, "Cannot create references to elements of a temporary array expression");
|
||||
}
|
||||
CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value = 1;
|
||||
}
|
||||
|
||||
opline->opcode = ZEND_FETCH_DIM_TMP_VAR;
|
||||
opline->result.op_type = IS_VAR;
|
||||
opline->result.u.EA.type = 0;
|
||||
@@ -3017,7 +3031,11 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token TSRMLS_DC)
|
||||
result_key = opline->result;
|
||||
}
|
||||
|
||||
zend_do_assign(&dummy, value, &result_value TSRMLS_CC);
|
||||
if (1 && assign_by_ref) {
|
||||
zend_do_assign_ref(&dummy, value, &result_value TSRMLS_CC);
|
||||
} else {
|
||||
zend_do_assign(&dummy, value, &result_value TSRMLS_CC);
|
||||
}
|
||||
CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED;
|
||||
if (key->op_type != IS_UNUSED) {
|
||||
zend_do_assign(&dummy, key, &result_key TSRMLS_CC);
|
||||
|
||||
+7
-6
@@ -405,7 +405,7 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC
|
||||
void zend_do_instanceof(znode *result, znode *expr, znode *class_znode, int type TSRMLS_DC);
|
||||
|
||||
void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable TSRMLS_DC);
|
||||
void zend_do_foreach_cont(znode *value, znode *key, znode *as_token TSRMLS_DC);
|
||||
void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC);
|
||||
void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token TSRMLS_DC);
|
||||
|
||||
void zend_do_declare_begin(TSRMLS_D);
|
||||
@@ -684,11 +684,12 @@ int zendlex(znode *zendlval TSRMLS_DC);
|
||||
|
||||
|
||||
/* variable parsing type (compile-time) */
|
||||
#define ZEND_PARSED_MEMBER (1<<0)
|
||||
#define ZEND_PARSED_METHOD_CALL (1<<1)
|
||||
#define ZEND_PARSED_STATIC_MEMBER (1<<2)
|
||||
#define ZEND_PARSED_FUNCTION_CALL (1<<3)
|
||||
#define ZEND_PARSED_VARIABLE (1<<4)
|
||||
#define ZEND_PARSED_MEMBER (1<<0)
|
||||
#define ZEND_PARSED_METHOD_CALL (1<<1)
|
||||
#define ZEND_PARSED_STATIC_MEMBER (1<<2)
|
||||
#define ZEND_PARSED_FUNCTION_CALL (1<<3)
|
||||
#define ZEND_PARSED_VARIABLE (1<<4)
|
||||
#define ZEND_PARSED_REFERENCE_VARIABLE (1<<5)
|
||||
|
||||
|
||||
/* unset types */
|
||||
|
||||
@@ -3510,6 +3510,10 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS)
|
||||
array_init(result);
|
||||
|
||||
|
||||
if (EX(opline)->extended_value) {
|
||||
SEPARATE_ZVAL_IF_NOT_REF(value);
|
||||
(*value)->is_ref = 1;
|
||||
}
|
||||
(*value)->refcount++;
|
||||
zend_hash_index_update(result->value.ht, 0, value, sizeof(zval *), NULL);
|
||||
|
||||
|
||||
@@ -207,8 +207,8 @@ unticked_statement:
|
||||
| expr ';' { zend_do_free(&$1 TSRMLS_CC); }
|
||||
| T_USE use_filename ';' { zend_error(E_COMPILE_ERROR,"use: Not yet supported. Please use include_once() or require_once()"); zval_dtor(&$2.u.constant); }
|
||||
| T_UNSET '(' unset_variables ')' ';'
|
||||
| T_FOREACH '(' variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 1 TSRMLS_CC); } w_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); }
|
||||
| T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 TSRMLS_CC); } w_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); }
|
||||
| T_FOREACH '(' variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 1 TSRMLS_CC); } foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); }
|
||||
| T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 TSRMLS_CC); } w_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); }
|
||||
| T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); }
|
||||
| ';' /* empty statement */
|
||||
| T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}'
|
||||
@@ -297,8 +297,14 @@ interface_list:
|
||||
;
|
||||
|
||||
foreach_optional_arg:
|
||||
/* empty */ { $$.op_type = IS_UNUSED; }
|
||||
| T_DOUBLE_ARROW w_variable { $$ = $2; }
|
||||
/* empty */ { $$.op_type = IS_UNUSED; }
|
||||
| T_DOUBLE_ARROW foreach_variable { $$ = $2; }
|
||||
;
|
||||
|
||||
|
||||
foreach_variable:
|
||||
w_variable { $$ = $1; }
|
||||
| '&' w_variable { $$ = $2; $$.u.EA.type |= ZEND_PARSED_REFERENCE_VARIABLE; }
|
||||
;
|
||||
|
||||
for_statement:
|
||||
|
||||
Reference in New Issue
Block a user