Skip to content

Commit d8696f9

Browse files
Girgiasiluuu1994arnaud-lb
authored
[RFC] Path to Saner Increment/Decrement operators (#10358)
* Add behavioural tests for incdec operators * Add support to ++/-- for objects castable to _IS_NUMBER * Add str_increment() function * Add str_decrement() function RFC: https://wiki.php.net/rfc/saner-inc-dec-operators Co-authored-by: Ilija Tovilo <[email protected]> Co-authored-by: Arnaud Le Blanc <[email protected]>
1 parent 2f318cf commit d8696f9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1897
-361
lines changed

UPGRADING

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ PHP 8.3 UPGRADE NOTES
118118
4. Deprecated Functionality
119119
========================================
120120

121+
- Core
122+
. Using the ++ operator on empty, non-numeric, or non-alphanumeric strings
123+
is now deprecated. Moreover, incrementing non-numeric strings is soft
124+
deprecated and the new str_increment() function should be used instead.
125+
RFC: https://wiki.php.net/rfc/saner-inc-dec-operators
126+
. Using the -- operator on empty or non-numeric strings is now deprecated.
127+
RFC: https://wiki.php.net/rfc/saner-inc-dec-operators
128+
121129
- Intl
122130
. The U_MULTIPLE_DECIMAL_SEP*E*RATORS constant had been deprecated, using
123131
the U_MULTIPLE_DECIMAL_SEP*A*RATORS instead is recommended.
@@ -303,6 +311,10 @@ PHP 8.3 UPGRADE NOTES
303311
- Sockets:
304312
. Added socket_atmark to checks if the socket is OOB marked.
305313

314+
- Standard:
315+
. Added the str_increment() and str_decrement() functions.
316+
RFC: https://wiki.php.net/rfc/saner-inc-dec-operators
317+
306318
- Zip:
307319
. Added ZipArchive::setArchiveFlag and ZipArchive::getArchiveFlag methods.
308320

@@ -324,6 +336,13 @@ PHP 8.3 UPGRADE NOTES
324336
not reachable except by iterating over the WeakMap (reachability via
325337
iteration is considered weak). Previously, such entries would never be
326338
automatically removed. (See GH-10932.)
339+
. The ++ and -- operators now emit warnings when attempting to increment
340+
values of type bool as this will change in the next major version.
341+
A warning is emitted when trying to decrement values of type null, as
342+
this will change in the next major version.
343+
Internal objects that implement an _IS_NUMBER cast but not a do_operator
344+
handler that overrides addition and substraction now can be incremented
345+
and decrement as if one would do $o += 1 or $o -= 1
327346

328347
- DOM:
329348
. The DOM lifetime mechanism has been reworked such that implicitly removed

Zend/Optimizer/sccp.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -664,9 +664,14 @@ static inline zend_result ct_eval_assign_obj(zval *result, zval *value, const zv
664664
}
665665

666666
static inline zend_result ct_eval_incdec(zval *result, uint8_t opcode, zval *op1) {
667+
/* As of PHP 8.3 with the warning/deprecation notices any type other than int/double/null will emit a diagnostic
667668
if (Z_TYPE_P(op1) == IS_ARRAY || IS_PARTIAL_ARRAY(op1)) {
668669
return FAILURE;
669670
}
671+
*/
672+
if (Z_TYPE_P(op1) != IS_LONG && Z_TYPE_P(op1) != IS_DOUBLE && Z_TYPE_P(op1) != IS_NULL) {
673+
return FAILURE;
674+
}
670675

671676
ZVAL_COPY(result, op1);
672677
if (opcode == ZEND_PRE_INC
@@ -675,6 +680,11 @@ static inline zend_result ct_eval_incdec(zval *result, uint8_t opcode, zval *op1
675680
|| opcode == ZEND_POST_INC_OBJ) {
676681
increment_function(result);
677682
} else {
683+
/* Decrement on null emits a deprecation notice */
684+
if (Z_TYPE_P(op1) == IS_NULL) {
685+
zval_ptr_dtor(result);
686+
return FAILURE;
687+
}
678688
decrement_function(result);
679689
}
680690
return SUCCESS;
@@ -1375,21 +1385,22 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
13751385
&& ctx->scdf.ssa->vars[ssa_op->op1_def].escape_state == ESCAPE_STATE_NO_ESCAPE) {
13761386
zval tmp1, tmp2;
13771387

1378-
if (ct_eval_fetch_obj(&tmp1, op1, op2) == SUCCESS
1379-
&& ct_eval_incdec(&tmp2, opline->opcode, &tmp1) == SUCCESS) {
1380-
1381-
dup_partial_object(&zv, op1);
1382-
ct_eval_assign_obj(&zv, &tmp2, op2);
1383-
if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
1384-
SET_RESULT(result, &tmp2);
1385-
} else {
1386-
SET_RESULT(result, &tmp1);
1388+
if (ct_eval_fetch_obj(&tmp1, op1, op2) == SUCCESS) {
1389+
if (ct_eval_incdec(&tmp2, opline->opcode, &tmp1) == SUCCESS) {
1390+
dup_partial_object(&zv, op1);
1391+
ct_eval_assign_obj(&zv, &tmp2, op2);
1392+
if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
1393+
SET_RESULT(result, &tmp2);
1394+
} else {
1395+
SET_RESULT(result, &tmp1);
1396+
}
1397+
zval_ptr_dtor_nogc(&tmp1);
1398+
zval_ptr_dtor_nogc(&tmp2);
1399+
SET_RESULT(op1, &zv);
1400+
zval_ptr_dtor_nogc(&zv);
1401+
break;
13871402
}
13881403
zval_ptr_dtor_nogc(&tmp1);
1389-
zval_ptr_dtor_nogc(&tmp2);
1390-
SET_RESULT(op1, &zv);
1391-
zval_ptr_dtor_nogc(&zv);
1392-
break;
13931404
}
13941405
}
13951406
}
@@ -2109,7 +2120,7 @@ static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var,
21092120
break;
21102121
default:
21112122
break;
2112-
}
2123+
}
21132124
}
21142125
/* we cannot remove instruction that defines other variables */
21152126
return 0;

Zend/Optimizer/zend_inference.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4681,9 +4681,11 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
46814681
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
46824682
case ZEND_PRE_INC:
46834683
case ZEND_POST_INC:
4684+
return (t1 & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4685+
/* null emits a warning as it has no effect compared to ++ which converts the value to 1 */
46844686
case ZEND_PRE_DEC:
46854687
case ZEND_POST_DEC:
4686-
return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4688+
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
46874689
case ZEND_BOOL_NOT:
46884690
case ZEND_JMPZ:
46894691
case ZEND_JMPNZ:

Zend/tests/decrement_001.phpt

Lines changed: 0 additions & 67 deletions
This file was deleted.

Zend/tests/decrement_001_64bit.phpt

Lines changed: 0 additions & 67 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Decrementing min int values 32bit
3+
--SKIPIF--
4+
<?php if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); ?>
5+
--INI--
6+
precision=14
7+
--FILE--
8+
<?php
9+
10+
$values = [
11+
-PHP_INT_MAX-1,
12+
(string)(-PHP_INT_MAX-1),
13+
];
14+
15+
foreach ($values as $var) {
16+
$var--;
17+
var_dump($var);
18+
}
19+
20+
echo "Done\n";
21+
?>
22+
--EXPECT--
23+
float(-2147483649)
24+
float(-2147483649)
25+
Done
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Decrementing min int values 64bit
3+
--SKIPIF--
4+
<?php if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); ?>
5+
--INI--
6+
precision=14
7+
--FILE--
8+
<?php
9+
10+
$values = [
11+
-PHP_INT_MAX-1,
12+
(string)(-PHP_INT_MAX-1),
13+
];
14+
15+
foreach ($values as $var) {
16+
$var--;
17+
var_dump($var);
18+
}
19+
20+
echo "Done\n";
21+
?>
22+
--EXPECT--
23+
float(-9.223372036854776E+18)
24+
float(-9.223372036854776E+18)
25+
Done
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Error handler can change type of operand of --
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function () {
7+
global $x;
8+
$x = 1;
9+
});
10+
11+
$x = '';
12+
$x--;
13+
var_dump($x);
14+
15+
?>
16+
DONE
17+
--EXPECT--
18+
int(-1)
19+
DONE

0 commit comments

Comments
 (0)