Skip to content

Commit

Permalink
Deprecate alternative array access syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
rjhdby authored and nikic committed Jul 19, 2019
1 parent d5943f5 commit d574df6
Show file tree
Hide file tree
Showing 19 changed files with 120 additions and 52 deletions.
3 changes: 3 additions & 0 deletions UPGRADING
Expand Up @@ -348,6 +348,9 @@ PHP 7.4 UPGRADE NOTES
$a ? $b : ($c ? $d : $e)

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
ReflectionMethod::getClosure() and closure rebinding is deprecated. Doing
so is equivalent to calling a non-static method statically, which has been
Expand Down
3 changes: 3 additions & 0 deletions Zend/tests/036.phpt
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
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
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
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
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
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 @@ -8745,7 +8749,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 @@ -8799,9 +8803,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
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
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
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
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
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
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
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
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
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
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
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
@@ -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

0 comments on commit d574df6

Please sign in to comment.