Skip to content

Deprecate curly brace syntax for array/string offset access #4416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Zend/tests/036.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ $a{function() { }} = 1;

?>
--EXPECTF--

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Warning: Illegal offset type in %s on line %d

Warning: Illegal offset type in %s on line %d
8 changes: 4 additions & 4 deletions Zend/tests/bug71572.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Bug #71572: String offset assignment from an empty string inserts null byte
<?php

$str = "abc";
var_dump($str{0} = "");
var_dump($str{1} = "");
var_dump($str{3} = "");
var_dump($str{10} = "");
var_dump($str[0] = "");
var_dump($str[1] = "");
var_dump($str[3] = "");
var_dump($str[10] = "");
var_dump($str);
?>
==DONE==
Expand Down
26 changes: 26 additions & 0 deletions Zend/tests/constant_expressions_coalesce.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@ Constant expressions with null coalescing operator ??

const A = [1 => [[]]];

// should produce deprecation notices
const D_1 = null ?? A[1]{'undefined'}['index'] ?? 1;
const D_2 = null ?? A['undefined']{'index'} ?? 2;
const D_3 = null ?? A[1]{0}{2} ?? 3; // 2 deprecation notices
const D_4 = A[1]{0} ?? 4;

const T_1 = null ?? A[1]['undefined']['index'] ?? 1;
const T_2 = null ?? A['undefined']['index'] ?? 2;
const T_3 = null ?? A[1][0][2] ?? 3;
const T_4 = A[1][0][2] ?? 4;
const T_5 = null ?? __LINE__;
const T_6 = __LINE__ ?? "bar";

var_dump(D_1);
var_dump(D_2);
var_dump(D_3);
var_dump(D_4);

var_dump(T_1);
var_dump(T_2);
var_dump(T_3);
Expand All @@ -31,6 +42,21 @@ var_dump((new class { public $var = A[1][0][2] ?? 4; })->var);

?>
--EXPECTF--

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d
int(1)
int(2)
int(3)
array(0) {
}
int(1)
int(2)
int(3)
Expand Down
18 changes: 9 additions & 9 deletions Zend/tests/str_offset_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,31 @@ $str = "abcdefghijklmno";
$i = 3;
$j = -4;

$str{2} = 'C';
$str[2] = 'C';
var_dump($str);

$str{$i} = 'Z';
$str[$i] = 'Z';
var_dump($str);

$str{-5} = 'P';
$str[-5] = 'P';
var_dump($str);

$str{$j} = 'Q';
$str[$j] = 'Q';
var_dump($str);

$str{-20} = 'Y';
$str[-20] = 'Y';
var_dump($str);

$str{-strlen($str)} = strtoupper($str{0}); /* An exotic ucfirst() ;) */
$str[-strlen($str)] = strtoupper($str[0]); /* An exotic ucfirst() ;) */
var_dump($str);

$str{20} = 'N';
$str[20] = 'N';
var_dump($str);

$str{-2} = 'UFO';
$str[-2] = 'UFO';
var_dump($str);

$str{-$i} = $str{$j*2};
$str[-$i] = $str[$j*2];
var_dump($str);
?>
--EXPECTF--
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
zval_ptr_dtor_nogc(&op1);
ret = FAILURE;
} else {
zend_fetch_dimension_const(result, &op1, &op2, (ast->attr == ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);
zend_fetch_dimension_const(result, &op1, &op2, (ast->attr & ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);

zval_ptr_dtor_nogc(&op1);
zval_ptr_dtor_nogc(&op2);
Expand Down
15 changes: 12 additions & 3 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -2371,6 +2371,10 @@ static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node)

static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
{
if (ast->attr == ZEND_DIM_ALTERNATIVE_SYNTAX) {
zend_error(E_DEPRECATED, "Array and string offset access syntax with curly braces is deprecated");
}

zend_ast *var_ast = ast->child[0];
zend_ast *dim_ast = ast->child[1];
zend_op *opline;
Expand Down Expand Up @@ -8744,7 +8748,7 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
case ZEND_AST_COALESCE:
/* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
if (ast->child[0]->kind == ZEND_AST_DIM) {
ast->child[0]->attr = ZEND_DIM_IS;
ast->child[0]->attr |= ZEND_DIM_IS;
}
zend_eval_const_expr(&ast->child[0]);

Expand Down Expand Up @@ -8798,9 +8802,14 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
}

if (ast->attr & ZEND_DIM_ALTERNATIVE_SYNTAX) {
ast->attr &= ~ZEND_DIM_ALTERNATIVE_SYNTAX; /* remove flag to avoid duplicate warning */
zend_error(E_DEPRECATED, "Array and string offset access syntax with curly braces is deprecated");
}

/* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
if (ast->attr == ZEND_DIM_IS && ast->child[0]->kind == ZEND_AST_DIM) {
ast->child[0]->attr = ZEND_DIM_IS;
if (ast->attr & ZEND_DIM_IS && ast->child[0]->kind == ZEND_AST_DIM) {
ast->child[0]->attr |= ZEND_DIM_IS;
}

zend_eval_const_expr(&ast->child[0]);
Expand Down
3 changes: 2 additions & 1 deletion Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,8 @@ void zend_assert_valid_class_name(const zend_string *const_name);
#define ZEND_SEND_BY_REF 1u
#define ZEND_SEND_PREFER_REF 2u

#define ZEND_DIM_IS 1
#define ZEND_DIM_IS (1 << 0) /* isset fetch needed for null coalesce */
#define ZEND_DIM_ALTERNATIVE_SYNTAX (1 << 1) /* deprecated curly brace usage */

#define IS_CONSTANT_UNQUALIFIED 0x010
#define IS_CONSTANT_CLASS 0x080 /* __CLASS__ in trait */
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ callable_variable:
| constant '[' optional_expr ']'
{ $$ = zend_ast_create(ZEND_AST_DIM, $1, $3); }
| dereferencable '{' expr '}'
{ $$ = zend_ast_create(ZEND_AST_DIM, $1, $3); }
{ $$ = zend_ast_create_ex(ZEND_AST_DIM, ZEND_DIM_ALTERNATIVE_SYNTAX, $1, $3); }
| dereferencable T_OBJECT_OPERATOR property_name argument_list
{ $$ = zend_ast_create(ZEND_AST_METHOD_CALL, $1, $3, $4); }
| function_call { $$ = $1; }
Expand Down
2 changes: 1 addition & 1 deletion ext/bz2/tests/005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ $data = bzcompress($string);
$data2 = bzcompress($string, 1, 10);

$data3 = $data2;
$data3{3} = 0;
$data3[3] = 0;

var_dump(bzdecompress());
var_dump(bzdecompress(1,1,1));
Expand Down
4 changes: 2 additions & 2 deletions ext/exif/tests/bug64739.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ if ($headers1 === false) {
exit;
}

var_dump($headers1['Title']{0} === '?');
var_dump($headers1['Author']{0} === '?');
var_dump($headers1['Title'][0] === '?');
var_dump($headers1['Author'][0] === '?');

ini_set('exif.decode_unicode_motorola', 'UCS-2LE');

Expand Down
2 changes: 1 addition & 1 deletion ext/opcache/tests/phi_remove_001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function getOnlyMPEGaudioInfoBruteForce($info) {
if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
$WhereWeWere = mftell();
$next4 = test(4);
if ($next4{0} == "\xFF") {
if ($next4[0] == "\xFF") {
if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
$MPEGaudioHeaderDecodeCache[$next4] = MPEGaudioHeaderDecode($next4);
}
Expand Down
2 changes: 1 addition & 1 deletion ext/zlib/tests/005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var_dump(gzuncompress("", 9));

var_dump(gzuncompress($data1));
var_dump(gzuncompress($data2));
$data2{4} = 0;
$data2[4] = 0;
var_dump(gzuncompress($data2));

echo "Done\n";
Expand Down
2 changes: 1 addition & 1 deletion ext/zlib/tests/006.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var_dump(gzinflate("asdf", 9));

var_dump(gzinflate($data1));
var_dump(gzinflate($data2));
$data2{4} = 0;
$data2[4] = 0;
var_dump(gzinflate($data2));

echo "Done\n";
Expand Down
8 changes: 4 additions & 4 deletions run-tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -2944,12 +2944,12 @@ function settings2params($ini_settings)
$settings .= " -d \"$name=$val\"";
}
} else {
if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value{0} == '"') {
if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value[0] == '"') {
$len = strlen($value);

if ($value{$len - 1} == '"') {
$value{0} = "'";
$value{$len - 1} = "'";
if ($value[$len - 1] == '"') {
$value[0] = "'";
$value[$len - 1] = "'";
}
} else {
$value = addslashes($value);
Expand Down
30 changes: 15 additions & 15 deletions sapi/fpm/tests/fcgi.inc
Original file line number Diff line number Diff line change
Expand Up @@ -362,19 +362,19 @@ class Client

while ($p != $length) {

$nlen = ord($data{$p++});
$nlen = ord($data[$p++]);
if ($nlen >= 128) {
$nlen = ($nlen & 0x7F << 24);
$nlen |= (ord($data{$p++}) << 16);
$nlen |= (ord($data{$p++}) << 8);
$nlen |= (ord($data{$p++}));
$nlen |= (ord($data[$p++]) << 16);
$nlen |= (ord($data[$p++]) << 8);
$nlen |= (ord($data[$p++]));
}
$vlen = ord($data{$p++});
$vlen = ord($data[$p++]);
if ($vlen >= 128) {
$vlen = ($nlen & 0x7F << 24);
$vlen |= (ord($data{$p++}) << 16);
$vlen |= (ord($data{$p++}) << 8);
$vlen |= (ord($data{$p++}));
$vlen |= (ord($data[$p++]) << 16);
$vlen |= (ord($data[$p++]) << 8);
$vlen |= (ord($data[$p++]));
}
$array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen);
$p += ($nlen + $vlen);
Expand All @@ -392,12 +392,12 @@ class Client
private function decodePacketHeader($data)
{
$ret = array();
$ret['version'] = ord($data{0});
$ret['type'] = ord($data{1});
$ret['requestId'] = (ord($data{2}) << 8) + ord($data{3});
$ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5});
$ret['paddingLength'] = ord($data{6});
$ret['reserved'] = ord($data{7});
$ret['version'] = ord($data[0]);
$ret['type'] = ord($data[1]);
$ret['requestId'] = (ord($data[2]) << 8) + ord($data[3]);
$ret['contentLength'] = (ord($data[4]) << 8) + ord($data[5]);
$ret['paddingLength'] = ord($data[6]);
$ret['reserved'] = ord($data[7]);
return $ret;
}

Expand Down Expand Up @@ -634,7 +634,7 @@ class Client
// Reset timeout
$this->set_ms_timeout($this->_readWriteTimeout);

switch (ord($resp['content']{4})) {
switch (ord($resp['content'][4])) {
case self::CANT_MPX_CONN:
throw new \Exception('This app can\'t multiplex [CANT_MPX_CONN]');
break;
Expand Down
2 changes: 1 addition & 1 deletion tests/strings/offsets_chaining_2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ error_reporting=E_ALL | E_DEPRECATED
--FILE--
<?php
$string = "foobar";
var_dump($string{0}{0}[0][0]);
var_dump($string[0][0][0][0]);
?>
--EXPECT--
string(1) "f"
2 changes: 1 addition & 1 deletion tests/strings/offsets_chaining_4.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ error_reporting=E_ALL | E_DEPRECATED
--FILE--
<?php
$string = "foobar";
var_dump(isset($string{0}{0}[0][0]));
var_dump(isset($string[0][0][0][0]));
?>
--EXPECT--
bool(true)
38 changes: 32 additions & 6 deletions tests/strings/offsets_general.phpt
Original file line number Diff line number Diff line change
@@ -1,24 +1,46 @@
--TEST--
testing the behavior of string offsets
--INI--
error_reporting=E_ALL | E_DEPRECATED
--FILE--
<?php
$string = "foobar";
const FOO = "BAR"[0];
var_dump(FOO);
var_dump($string[0]);
var_dump($string[1]);
var_dump(isset($string[0]));
var_dump(isset($string[0][0]));
var_dump($string["foo"]);
var_dump(isset($string["foo"]["bar"]));
var_dump($string{0});

const FOO_DEPRECATED = "BAR"{0};
var_dump(FOO_DEPRECATED);
var_dump([$string{0}]); // 1 notice
var_dump($string{1});
var_dump(isset($string{0}));
var_dump(isset($string{0}{0}));
var_dump(isset($string{0}{0})); // 2 notices
var_dump($string{"foo"});
var_dump(isset($string{"foo"}{"bar"}));
var_dump(isset($string{"foo"}{"bar"})); // 2 notices
?>
--EXPECTF--

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d

Deprecated: Array and string offset access syntax with curly braces is deprecated in %s line %d
string(1) "B"
string(1) "f"
string(1) "o"
bool(true)
Expand All @@ -27,7 +49,11 @@ bool(true)
Warning: Illegal string offset 'foo' in %s line %d
string(1) "f"
bool(false)
string(1) "f"
string(1) "B"
array(1) {
[0]=>
string(1) "f"
}
string(1) "o"
bool(true)
bool(true)
Expand Down