rfc:increment_decrement_fixes

This is an old revision of the document!


PHP RFC: Increment/Decrement Fixes

Introduction

The increment and decrement operators (++$a, $a++, --$a, $a--) mostly behave the same as adding 1 to the variable. However, because they are implemented separately, there are a handful of anomalies regarding non-integer values, which do are not incremented consistently with an integer cast. In particular, this RFC focuses on null, boolean, and array values.

Intuitively, the ++ and -- operators are equivalent to “add 1 to variable” and “subtract 1 from variable”, respectively. As such, it would be expected that $a=$a+1, $a+=1, and ++$a would end up with the same value in $a; and likewise, $a=$a-1, $a-=1, and --$a.

This is currently not the case, because ++ and -- are implemented separately for each type via a switch statement in the engine. Rather than coercing the current value to an integer, the default case in this switch statement is to silently leave the value unchanged.

For null and boolean, addition and subtraction are based on casting to integer; for arrays, they throw an error; this RFC aims to make increment and decrement consistent in all three cases.

Proposal 1: Decrementing Null

The behaviour of null with ++ is consistent with it being coerced to int(0); however, with -- the null remains unchanged.

This behaviour has been raised as a bug at least three times (#20548, #25674, #41690). All three are closed, and it is documented in the manual, but there is no evidence that it is intentional behaviour rather than an entrenched bug retained for compatibility.

Discrepancies in behaviour of null are particularly problematic, since undefined variables, array items, and object properties are currently treated as having a value of null.

This RFC proposes to change the behaviour, so that $a=null; $a--; or $a=null; --$a; will result in $a holding -1. This brings it into line with all other mathematical operations, include $a++, which treat null as equivalent to 0.

Initial Value $a = $a + 1 $a += 1 ++$a, $a++ $a = $a - 1 $a -= 1 --$a, $a--
Current null 1 1 1 -1 -1 null
Proposed null 1 1 1 -1 -1 -1

Proposal 2: Incrementing and Decrementing Booleans

The behaviour of booleans with most mathematical operations is to treat false as 0 and true as 1. However, the ++ and -- operators currently leave boolean values unchanged.

This RFC proposes to change the behaviour so that it is in line with other mathematical contexts, as follows:

Initial Value $a = $a + 1 $a += 1 ++$a, $a++ $a = $a - 1 $a -= 1 --$a, $a--
Current true 2 2 true 0 0 true
Proposed true 2 2 2 0 0 0
Current false 1 1 false -1 -1 false
Proposed false 1 1 1 -1 -1 -1

Proposal 3: Error when incrementing or decrementing an array

Adding an integer to an array produces an “Unsupported operand types” error, but incrementing or decrementing it leaves it unchanged, with no Notice, Warning, or Error.

This RFC proposed to change the behaviour so that $a=[]; $a++; and $a=[]; $a--; raise the same error as $a = [] + 1;.

Initial Value $a = $a + 1 $a += 1 ++$a, $a++ $a = $a - 1 $a -= 1 --$a, $a--
Current any array Error Error no effect Error Error no effect
Proposed any array Error Error Error Error Error Error

Backward Incompatible Changes

The proposed changes to null and boolean handling are not backwards compatible. The current behaviour is not particularly useful, so it is unlikely that code is deliberately relying on it.

Proposed PHP Version(s)

8.0

RFC Impact

Open Issues

None raised yet.

Unaffected PHP Functionality

* Undefined variables, array items, and object properties are currently treated as null for most purposes, including the ++ and -- operators. Changing this behaviour is out of scope of this RFC, and the behaviour of variables explicitly set to null would still need to be defined. * Similarly, most mathematical contexts will coerce null and false to 0, and true to 1; this RFC does not seek to change any cases where that logic is followed. Changes to that general principle might render this RFC obsolete, but might require a period of deprecation, so consistency of the current approach may still be valuable. * Strings overload the ++ and -- operators with complex behaviour not discussed here. Improving this deserves its own discussion, so has been left out of this RFC. * Objects and resources are currently left unchanged by ++ and --. However, their behaviour with normal addition and subtraction is not particularly intuitive, so this RFC doesn't propose to extend it to increment and decrement.

For reference, the current behaviour is as follows:

Initial Value $a = $a + 1 $a += 1 ++$a, $a++ $a = $a - 1 $a -= 1 --$a, $a--
any object 2 (with Notice) 2 (with Notice) no effect 0 (with Notice) 0 (with Notice) no effect
resource#1 2 2 no effect 0 0 no effect
resource#5 6 6 no effect 4 4 no effect

Proposed Voting Choices

* Should decrementing null result in -1? (Yes / No) * Should incrementing and decrementing booleans act the same as addition and subtraction? (Yes / No) * Should incrementing or decrementing an array throw an “Unsupported operand types” error? (Yes / No)

Patches and Tests

The implementation should be a simple addition to the increment_function and decrement_function definitions in Zend/zend_operators.c.

Implementation

TODO

References

Rejected Features

TODO

rfc/increment_decrement_fixes.1583086465.txt.gz · Last modified: 2020/03/01 18:14 by imsop