Skip to content

Commit 565892d

Browse files
committed
Implement const array/string dereference
RFC:https://wiki.php.net/rfc/constdereference
1 parent 739eda3 commit 565892d

8 files changed

+432
-39
lines changed

NEWS

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ PHP NEWS
66
. Drop Windows XP and 2003 support. (Pierre)
77
. World domination
88
. Improve set_exception_handler while doing reset.(Laruence)
9+
. Support constant array/string dereferencing. (Laruence)
910

1011
- Core:
1112
. Implemented FR #60738 (Allow 'set_error_handler' to handle NULL).

UPGRADING

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ PHP X.Y UPGRADE NOTES
2626
2. New Features
2727
========================================
2828

29+
- Support constant array/string dereferencing. (Laruence)
30+
(https://wiki.php.net/rfc/constdereference)
2931

3032
========================================
3133
2. Changes in SAPI modules

Zend/tests/const_dereference_001.phpt

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Const array deference
3+
--FILE--
4+
<?php
5+
error_reporting(E_ALL);
6+
7+
var_dump(array(1, 2, 3, 4,) [3]);
8+
var_dump(array(1, 2, 3, 4,) ['foo']);
9+
var_dump(array(array(1,2,3), array(4, 5, 6))[1][2]);
10+
11+
foreach (array(array(1, 2, 3))[0] as $var) {
12+
echo $var;
13+
}
14+
?>
15+
--EXPECTF--
16+
int(4)
17+
18+
Notice: Undefined index: foo in %sconst_dereference_001.php on line %d
19+
NULL
20+
int(6)
21+
123

Zend/tests/const_dereference_002.phpt

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Const string dereference
3+
--FILE--
4+
<?php
5+
error_reporting(E_ALL);
6+
7+
var_dump("foobar"[3]);
8+
var_dump("foobar"[2][0]);
9+
var_dump("foobar"["foo"]["bar"]);
10+
11+
--EXPECTF--
12+
string(1) "b"
13+
string(1) "o"
14+
15+
Warning: Illegal string offset 'foo' in %sconst_dereference_002.php on line %d
16+
17+
Warning: Illegal string offset 'bar' in %sconst_dereference_002.php on line %d
18+
string(1) "f"

Zend/tests/const_dereference_003.phpt

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Const array deference
3+
--FILE--
4+
<?php
5+
error_reporting(E_ALL);
6+
7+
var_dump([1, 2, 3, 4,][3]);
8+
var_dump([1, 2, 3, 4]['foo']);
9+
var_dump([array(1,2,3), [4, 5, 6]][1][2]);
10+
11+
foreach (array([1, 2, 3])[0] as $var) {
12+
echo $var;
13+
}
14+
?>
15+
--EXPECTF--
16+
int(4)
17+
18+
Notice: Undefined index: foo in %sconst_dereference_003.php on line %d
19+
NULL
20+
int(6)
21+
123

Zend/zend_language_parser.y

+11-2
Original file line numberDiff line numberDiff line change
@@ -789,8 +789,8 @@ expr_without_variable:
789789
| T_EXIT exit_expr { zend_do_exit(&$$, &$2 TSRMLS_CC); }
790790
| '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; }
791791
| scalar { $$ = $1; }
792-
| T_ARRAY '(' array_pair_list ')' { $$ = $3; }
793-
| '[' array_pair_list ']' { $$ = $2; }
792+
| combined_scalar_offset { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); }
793+
| combined_scalar { $$ = $1; }
794794
| '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); }
795795
| T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); }
796796
| function is_reference '(' { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); }
@@ -799,6 +799,15 @@ expr_without_variable:
799799
parameter_list ')' lexical_vars '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $5; }
800800
;
801801

802+
combined_scalar_offset:
803+
combined_scalar '[' dim_offset ']' { zend_do_begin_variable_parse(TSRMLS_C); fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
804+
| combined_scalar_offset '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
805+
| T_CONSTANT_ENCAPSED_STRING '[' dim_offset ']' { zend_do_begin_variable_parse(TSRMLS_C); fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
806+
807+
combined_scalar:
808+
T_ARRAY '(' array_pair_list ')' { $$ = $3; }
809+
| '[' array_pair_list ']' { $$ = $2; }
810+
802811
function:
803812
T_FUNCTION { $$.u.op.opline_num = CG(zend_lineno); }
804813
;

Zend/zend_vm_def.h

+14-5
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ ZEND_VM_HANDLER(89, ZEND_FETCH_IS, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)
11741174
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_IS);
11751175
}
11761176

1177-
ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, VAR|CV, CONST|TMP|VAR|CV)
1177+
ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)
11781178
{
11791179
USE_OPLINE
11801180
zend_free_op free_op1, free_op2;
@@ -1187,10 +1187,19 @@ ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, VAR|CV, CONST|TMP|VAR|CV)
11871187
EX_T(opline->op1.var).var.ptr_ptr) {
11881188
PZVAL_LOCK(*EX_T(opline->op1.var).var.ptr_ptr);
11891189
}
1190-
container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
1191-
zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC);
1192-
FREE_OP2();
1193-
FREE_OP1_VAR_PTR();
1190+
1191+
if (OP1_TYPE == IS_TMP_VAR || OP1_TYPE == IS_CONST) {
1192+
zval *container = GET_OP1_ZVAL_PTR(BP_VAR_R);
1193+
zend_fetch_dimension_address_read(&EX_T(opline->result.var), &container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC);
1194+
FREE_OP2();
1195+
FREE_OP1();
1196+
} else {
1197+
container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
1198+
zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC);
1199+
FREE_OP2();
1200+
FREE_OP1_VAR_PTR();
1201+
}
1202+
11941203
CHECK_EXCEPTION();
11951204
ZEND_VM_NEXT_OPCODE();
11961205
}

0 commit comments

Comments
 (0)