Deprecate alternative array access syntax

RFC: https://wiki.php.net/rfc/deprecate_curly_braces_array_access
This commit is contained in:
rjhdby 2019-03-13 13:51:31 +03:00 committed by Nikita Popov
parent d5943f5a11
commit d574df63dc
19 changed files with 120 additions and 52 deletions

View file

@ -348,6 +348,9 @@ PHP 7.4 UPGRADE NOTES
$a ? $b : ($c ? $d : $e) $a ? $b : ($c ? $d : $e)
RFC: https://wiki.php.net/rfc/ternary_associativity RFC: https://wiki.php.net/rfc/ternary_associativity
. The array and string offset access syntax using curly braces is deprecated.
Use $str[$idx] instead of $str{$idx}.
RFC: https://wiki.php.net/rfc/deprecate_curly_braces_array_access
. Unbinding $this of a non-static method through a combination of . Unbinding $this of a non-static method through a combination of
ReflectionMethod::getClosure() and closure rebinding is deprecated. Doing ReflectionMethod::getClosure() and closure rebinding is deprecated. Doing
so is equivalent to calling a non-static method statically, which has been so is equivalent to calling a non-static method statically, which has been

View file

@ -8,6 +8,9 @@ $a{function() { }} = 1;
?> ?>
--EXPECTF-- --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
Warning: Illegal offset type in %s on line %d Warning: Illegal offset type in %s on line %d

View file

@ -4,10 +4,10 @@ Bug #71572: String offset assignment from an empty string inserts null byte
<?php <?php
$str = "abc"; $str = "abc";
var_dump($str{0} = ""); var_dump($str[0] = "");
var_dump($str{1} = ""); var_dump($str[1] = "");
var_dump($str{3} = ""); var_dump($str[3] = "");
var_dump($str{10} = ""); var_dump($str[10] = "");
var_dump($str); var_dump($str);
?> ?>
==DONE== ==DONE==

View file

@ -5,6 +5,12 @@ Constant expressions with null coalescing operator ??
const A = [1 => [[]]]; 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_1 = null ?? A[1]['undefined']['index'] ?? 1;
const T_2 = null ?? A['undefined']['index'] ?? 2; const T_2 = null ?? A['undefined']['index'] ?? 2;
const T_3 = null ?? A[1][0][2] ?? 3; const T_3 = null ?? A[1][0][2] ?? 3;
@ -12,6 +18,11 @@ const T_4 = A[1][0][2] ?? 4;
const T_5 = null ?? __LINE__; const T_5 = null ?? __LINE__;
const T_6 = __LINE__ ?? "bar"; 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_1);
var_dump(T_2); var_dump(T_2);
var_dump(T_3); var_dump(T_3);
@ -31,6 +42,21 @@ var_dump((new class { public $var = A[1][0][2] ?? 4; })->var);
?> ?>
--EXPECTF-- --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(1)
int(2) int(2)
int(3) int(3)

View file

@ -8,31 +8,31 @@ $str = "abcdefghijklmno";
$i = 3; $i = 3;
$j = -4; $j = -4;
$str{2} = 'C'; $str[2] = 'C';
var_dump($str); var_dump($str);
$str{$i} = 'Z'; $str[$i] = 'Z';
var_dump($str); var_dump($str);
$str{-5} = 'P'; $str[-5] = 'P';
var_dump($str); var_dump($str);
$str{$j} = 'Q'; $str[$j] = 'Q';
var_dump($str); var_dump($str);
$str{-20} = 'Y'; $str[-20] = 'Y';
var_dump($str); var_dump($str);
$str{-strlen($str)} = strtoupper($str{0}); /* An exotic ucfirst() ;) */ $str[-strlen($str)] = strtoupper($str[0]); /* An exotic ucfirst() ;) */
var_dump($str); var_dump($str);
$str{20} = 'N'; $str[20] = 'N';
var_dump($str); var_dump($str);
$str{-2} = 'UFO'; $str[-2] = 'UFO';
var_dump($str); var_dump($str);
$str{-$i} = $str{$j*2}; $str[-$i] = $str[$j*2];
var_dump($str); var_dump($str);
?> ?>
--EXPECTF-- --EXPECTF--

View file

@ -714,7 +714,7 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
zval_ptr_dtor_nogc(&op1); zval_ptr_dtor_nogc(&op1);
ret = FAILURE; ret = FAILURE;
} else { } 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(&op1);
zval_ptr_dtor_nogc(&op2); zval_ptr_dtor_nogc(&op2);

View file

@ -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) /* {{{ */ 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 *var_ast = ast->child[0];
zend_ast *dim_ast = ast->child[1]; zend_ast *dim_ast = ast->child[1];
zend_op *opline; zend_op *opline;
@ -8745,7 +8749,7 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
case ZEND_AST_COALESCE: case ZEND_AST_COALESCE:
/* Set isset fetch indicator here, opcache disallows runtime altering of the AST */ /* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
if (ast->child[0]->kind == ZEND_AST_DIM) { 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]); zend_eval_const_expr(&ast->child[0]);
@ -8799,9 +8803,14 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading"); 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 */ /* 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) { if (ast->attr & ZEND_DIM_IS && 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]); zend_eval_const_expr(&ast->child[0]);

View file

@ -924,7 +924,8 @@ void zend_assert_valid_class_name(const zend_string *const_name);
#define ZEND_SEND_BY_REF 1u #define ZEND_SEND_BY_REF 1u
#define ZEND_SEND_PREFER_REF 2u #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_UNQUALIFIED 0x010
#define IS_CONSTANT_CLASS 0x080 /* __CLASS__ in trait */ #define IS_CONSTANT_CLASS 0x080 /* __CLASS__ in trait */

View file

@ -1155,7 +1155,7 @@ callable_variable:
| constant '[' optional_expr ']' | constant '[' optional_expr ']'
{ $$ = zend_ast_create(ZEND_AST_DIM, $1, $3); } { $$ = zend_ast_create(ZEND_AST_DIM, $1, $3); }
| dereferencable '{' expr '}' | 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 | dereferencable T_OBJECT_OPERATOR property_name argument_list
{ $$ = zend_ast_create(ZEND_AST_METHOD_CALL, $1, $3, $4); } { $$ = zend_ast_create(ZEND_AST_METHOD_CALL, $1, $3, $4); }
| function_call { $$ = $1; } | function_call { $$ = $1; }

View file

@ -21,7 +21,7 @@ $data = bzcompress($string);
$data2 = bzcompress($string, 1, 10); $data2 = bzcompress($string, 1, 10);
$data3 = $data2; $data3 = $data2;
$data3{3} = 0; $data3[3] = 0;
var_dump(bzdecompress()); var_dump(bzdecompress());
var_dump(bzdecompress(1,1,1)); var_dump(bzdecompress(1,1,1));

View file

@ -16,8 +16,8 @@ if ($headers1 === false) {
exit; exit;
} }
var_dump($headers1['Title']{0} === '?'); var_dump($headers1['Title'][0] === '?');
var_dump($headers1['Author']{0} === '?'); var_dump($headers1['Author'][0] === '?');
ini_set('exif.decode_unicode_motorola', 'UCS-2LE'); ini_set('exif.decode_unicode_motorola', 'UCS-2LE');

View file

@ -31,7 +31,7 @@ function getOnlyMPEGaudioInfoBruteForce($info) {
if ($MPEGaudioHeaderLengthCache[$head4] > 4) { if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
$WhereWeWere = mftell(); $WhereWeWere = mftell();
$next4 = test(4); $next4 = test(4);
if ($next4{0} == "\xFF") { if ($next4[0] == "\xFF") {
if (!isset($MPEGaudioHeaderDecodeCache[$next4])) { if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
$MPEGaudioHeaderDecodeCache[$next4] = MPEGaudioHeaderDecode($next4); $MPEGaudioHeaderDecodeCache[$next4] = MPEGaudioHeaderDecode($next4);
} }

View file

@ -28,7 +28,7 @@ var_dump(gzuncompress("", 9));
var_dump(gzuncompress($data1)); var_dump(gzuncompress($data1));
var_dump(gzuncompress($data2)); var_dump(gzuncompress($data2));
$data2{4} = 0; $data2[4] = 0;
var_dump(gzuncompress($data2)); var_dump(gzuncompress($data2));
echo "Done\n"; echo "Done\n";

View file

@ -29,7 +29,7 @@ var_dump(gzinflate("asdf", 9));
var_dump(gzinflate($data1)); var_dump(gzinflate($data1));
var_dump(gzinflate($data2)); var_dump(gzinflate($data2));
$data2{4} = 0; $data2[4] = 0;
var_dump(gzinflate($data2)); var_dump(gzinflate($data2));
echo "Done\n"; echo "Done\n";

View file

@ -2944,12 +2944,12 @@ function settings2params($ini_settings)
$settings .= " -d \"$name=$val\""; $settings .= " -d \"$name=$val\"";
} }
} else { } 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); $len = strlen($value);
if ($value{$len - 1} == '"') { if ($value[$len - 1] == '"') {
$value{0} = "'"; $value[0] = "'";
$value{$len - 1} = "'"; $value[$len - 1] = "'";
} }
} else { } else {
$value = addslashes($value); $value = addslashes($value);

View file

@ -362,19 +362,19 @@ class Client
while ($p != $length) { while ($p != $length) {
$nlen = ord($data{$p++}); $nlen = ord($data[$p++]);
if ($nlen >= 128) { if ($nlen >= 128) {
$nlen = ($nlen & 0x7F << 24); $nlen = ($nlen & 0x7F << 24);
$nlen |= (ord($data{$p++}) << 16); $nlen |= (ord($data[$p++]) << 16);
$nlen |= (ord($data{$p++}) << 8); $nlen |= (ord($data[$p++]) << 8);
$nlen |= (ord($data{$p++})); $nlen |= (ord($data[$p++]));
} }
$vlen = ord($data{$p++}); $vlen = ord($data[$p++]);
if ($vlen >= 128) { if ($vlen >= 128) {
$vlen = ($nlen & 0x7F << 24); $vlen = ($nlen & 0x7F << 24);
$vlen |= (ord($data{$p++}) << 16); $vlen |= (ord($data[$p++]) << 16);
$vlen |= (ord($data{$p++}) << 8); $vlen |= (ord($data[$p++]) << 8);
$vlen |= (ord($data{$p++})); $vlen |= (ord($data[$p++]));
} }
$array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen); $array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen);
$p += ($nlen + $vlen); $p += ($nlen + $vlen);
@ -392,12 +392,12 @@ class Client
private function decodePacketHeader($data) private function decodePacketHeader($data)
{ {
$ret = array(); $ret = array();
$ret['version'] = ord($data{0}); $ret['version'] = ord($data[0]);
$ret['type'] = ord($data{1}); $ret['type'] = ord($data[1]);
$ret['requestId'] = (ord($data{2}) << 8) + ord($data{3}); $ret['requestId'] = (ord($data[2]) << 8) + ord($data[3]);
$ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5}); $ret['contentLength'] = (ord($data[4]) << 8) + ord($data[5]);
$ret['paddingLength'] = ord($data{6}); $ret['paddingLength'] = ord($data[6]);
$ret['reserved'] = ord($data{7}); $ret['reserved'] = ord($data[7]);
return $ret; return $ret;
} }
@ -634,7 +634,7 @@ class Client
// Reset timeout // Reset timeout
$this->set_ms_timeout($this->_readWriteTimeout); $this->set_ms_timeout($this->_readWriteTimeout);
switch (ord($resp['content']{4})) { switch (ord($resp['content'][4])) {
case self::CANT_MPX_CONN: case self::CANT_MPX_CONN:
throw new \Exception('This app can\'t multiplex [CANT_MPX_CONN]'); throw new \Exception('This app can\'t multiplex [CANT_MPX_CONN]');
break; break;

View file

@ -5,7 +5,7 @@ error_reporting=E_ALL | E_DEPRECATED
--FILE-- --FILE--
<?php <?php
$string = "foobar"; $string = "foobar";
var_dump($string{0}{0}[0][0]); var_dump($string[0][0][0][0]);
?> ?>
--EXPECT-- --EXPECT--
string(1) "f" string(1) "f"

View file

@ -5,7 +5,7 @@ error_reporting=E_ALL | E_DEPRECATED
--FILE-- --FILE--
<?php <?php
$string = "foobar"; $string = "foobar";
var_dump(isset($string{0}{0}[0][0])); var_dump(isset($string[0][0][0][0]));
?> ?>
--EXPECT-- --EXPECT--
bool(true) bool(true)

View file

@ -1,24 +1,46 @@
--TEST-- --TEST--
testing the behavior of string offsets testing the behavior of string offsets
--INI--
error_reporting=E_ALL | E_DEPRECATED
--FILE-- --FILE--
<?php <?php
$string = "foobar"; $string = "foobar";
const FOO = "BAR"[0];
var_dump(FOO);
var_dump($string[0]); var_dump($string[0]);
var_dump($string[1]); var_dump($string[1]);
var_dump(isset($string[0])); var_dump(isset($string[0]));
var_dump(isset($string[0][0])); var_dump(isset($string[0][0]));
var_dump($string["foo"]); var_dump($string["foo"]);
var_dump(isset($string["foo"]["bar"])); 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($string{1});
var_dump(isset($string{0})); 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($string{"foo"});
var_dump(isset($string{"foo"}{"bar"})); var_dump(isset($string{"foo"}{"bar"})); // 2 notices
?> ?>
--EXPECTF-- --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) "f"
string(1) "o" string(1) "o"
bool(true) bool(true)
@ -27,7 +49,11 @@ bool(true)
Warning: Illegal string offset 'foo' in %s line %d Warning: Illegal string offset 'foo' in %s line %d
string(1) "f" string(1) "f"
bool(false) bool(false)
string(1) "f" string(1) "B"
array(1) {
[0]=>
string(1) "f"
}
string(1) "o" string(1) "o"
bool(true) bool(true)
bool(true) bool(true)