# PHP7 / foreach / references / ugly code / discrepancy to PHP 5.6

- Thread: https://externals.io/message/89150
- Original archive: https://news-web.php.net/php.internals/89150
- Started by Philip Hofstetter on 2015-11-10T16:48:54+00:00
- Messages: 6
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #89150 — Philip Hofstetter — 2015-11-10T16:48:54+00:00

URL: https://externals.io/message/89150#89150

Hi,

I'm having a cause of slightly ugly code that runs differently from PHP 5.6
to PHP 7 and I don't think this difference is documented, nor expected. As
I'm not sure whether this is an intended change or not, I'm asking here
firstr before making a bug report.

The code in question is

----
$b = [1, 2, 3];

foreach($b ?: [] as &$v){
    $v = $v*2;
    unset($v);
}

var_dump($b);
----
in PHP7, this produces

array(3) {
  [0] =>
  int(1)
  [1] =>
  int(2)
  [2] =>
  int(3)
}

whereas in PHP 5.6 and earlier, this produces

array(3) {
  [0] =>
  int(2)
  [1] =>
  int(4)
  [2] =>
  int(6)
}

what scares me about this is that in order to get the old behaviour in PHP7
back, you just have to get rid of the ?: operator:

foreach($b as &$v){

is fine

foreach($b ?: [] as &$v){

is not.

I guess this is related to
http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.foreach.by-value
 or
http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.foreach.by-ref,
but I'm not entirely sure whether this is actually intended behaviour -
it's certainly unexpected to me that applying ?: now always makes a copy
whereas before it didn't.

Philip



-- 
Sensational AG
Giesshübelstrasse 62c, Postfach 1966, 8021 Zürich
Tel. +41 43 544 09 60, Mobile  +41 79 341 01 99
info@sensational.ch, http://www.sensational.ch

---

## #89152 — Martin Amps — 2015-11-10T19:08:55+00:00

URL: https://externals.io/message/89150#89152 · In reply to: #89150

Here’s a 3v4l demonstrating this too:

https://3v4l.org/OXAd3 <https://3v4l.org/OXAd3>


> 
> 
> Hi,
> 
> I'm having a cause of slightly ugly code that runs differently from PHP 5.6
> to PHP 7 and I don't think this difference is documented, nor expected. As
> I'm not sure whether this is an intended change or not, I'm asking here
> firstr before making a bug report.
> 
> The code in question is
> 
> ----
> $b = [1, 2, 3];
> 
> foreach($b ?: [] as &$v){
>    $v = $v*2;
>    unset($v);
> }
> 
> var_dump($b);
> ----
> in PHP7, this produces
> 
> array(3) {
>  [0] =>
>  int(1)
>  [1] =>
>  int(2)
>  [2] =>
>  int(3)
> }
> 
> whereas in PHP 5.6 and earlier, this produces
> 
> array(3) {
>  [0] =>
>  int(2)
>  [1] =>
>  int(4)
>  [2] =>
>  int(6)
> }
> 
> what scares me about this is that in order to get the old behaviour in PHP7
> back, you just have to get rid of the ?: operator:
> 
> foreach($b as &$v){
> 
> is fine
> 
> foreach($b ?: [] as &$v){
> 
> is not.
> 
> I guess this is related to
> http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.foreach.by-value
> or
> http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.foreach.by-ref,
> but I'm not entirely sure whether this is actually intended behaviour -
> it's certainly unexpected to me that applying ?: now always makes a copy
> whereas before it didn't.
> 
> Philip
> 
> 
> 
> -- 
> Sensational AG
> Giesshübelstrasse 62c, Postfach 1966, 8021 Zürich
> Tel. +41 43 544 09 60, Mobile  +41 79 341 01 99
> info@sensational.ch, http://www.sensational.ch

---

## #89154 — Bishop Bettini — 2015-11-10T19:31:32+00:00

URL: https://externals.io/message/89150#89154 · In reply to: #89150

On Tue, Nov 10, 2015 at 11:48 AM, Philip Hofstetter <
phofstetter@sensational.ch> wrote:

> Hi,
> ...snip...
> I guess this is related to
>
> http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.foreach.by-value
>  or
>
> http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.foreach.by-ref
> ,
> but I'm not entirely sure whether this is actually intended behaviour -
> it's certainly unexpected to me that applying ?: now always makes a copy
> whereas before it didn't.
>

The issue may not be with foreach, but instead with the ?: ternary or the
optimizer. Maybe either:

1. It's a side-effect of merging the ZEND_QM_ASSIGN and ZEND_QM_ASSIGN_VAR
op codes.  (See PHP 5.6 ?: op code definitions
<https://github.com/php/php-src/blob/PHP-5.6/Zend/zend_vm_def.h#L4977-L5021>
and Same for PHP 7.0
<https://github.com/php/php-src/blob/master/Zend/zend_vm_def.h#L6945-L6977>
.)

2. The optimizer isn't handling the foreach scenario. (See Block pass
optimizer code
<https://github.com/php/php-src/blob/master/ext/opcache/Optimizer/block_pass.c#L574-L593>
.)

I don't see any change notes for either, so I'm guessing this is a bug.

bishop

---

## #89155 — Nikita Popov — 2015-11-10T19:45:07+00:00

URL: https://externals.io/message/89150#89155 · In reply to: #89150

On Tue, Nov 10, 2015 at 5:48 PM, Philip Hofstetter <
phofstetter@sensational.ch> wrote:

> Hi,
>
> I'm having a cause of slightly ugly code that runs differently from PHP 5.6
> to PHP 7 and I don't think this difference is documented, nor expected. As
> I'm not sure whether this is an intended change or not, I'm asking here
> firstr before making a bug report.
>
> The code in question is
>
> ----
> $b = [1, 2, 3];
>
> foreach($b ?: [] as &$v){
>     $v = $v*2;
>     unset($v);
> }
>
> var_dump($b);
> ----
> in PHP7, this produces
>
> array(3) {
>   [0] =>
>   int(1)
>   [1] =>
>   int(2)
>   [2] =>
>   int(3)
> }
>
> whereas in PHP 5.6 and earlier, this produces
>
> array(3) {
>   [0] =>
>   int(2)
>   [1] =>
>   int(4)
>   [2] =>
>   int(6)
> }
>
> what scares me about this is that in order to get the old behaviour in PHP7
> back, you just have to get rid of the ?: operator:
>
> foreach($b as &$v){
>
> is fine
>
> foreach($b ?: [] as &$v){
>
> is not.
>
> I guess this is related to
>
> http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.foreach.by-value
>  or
>
> http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.foreach.by-ref
> ,
> but I'm not entirely sure whether this is actually intended behaviour -
> it's certainly unexpected to me that applying ?: now always makes a copy
> whereas before it didn't.
>

This is a bug in PHP 5, which has been fixed in PHP 7 as a side-effect of
other changes. The new behavior is correct. This issue is tracked at
https://bugs.php.net/bug.php?id=70857.

Nikita

---

## #89156 — Adam Harvey — 2015-11-10T19:47:31+00:00

URL: https://externals.io/message/89150#89156 · In reply to: #89155

Hey Nikita,


> This is a bug in PHP 5, which has been fixed in PHP 7 as a side-effect of
> other changes. The new behavior is correct. This issue is tracked at
> https://bugs.php.net/bug.php?id=70857.

Are there any other variations on what expressions this changes the
behaviour of, or is it really just ternaries? Just trying to figure
out how to document this.

Thanks,

Adam

---

## #89177 — David Zuelke — 2015-11-11T13:33:49+00:00

URL: https://externals.io/message/89150#89177 · In reply to: #89155

Should this be in the UPGRADING notes?


> 
> 
> On Tue, Nov 10, 2015 at 5:48 PM, Philip Hofstetter <
> phofstetter@sensational.ch> wrote:
> 
> > […]
> 
> This is a bug in PHP 5, which has been fixed in PHP 7 as a side-effect of
> other changes. The new behavior is correct. This issue is tracked at
> https://bugs.php.net/bug.php?id=70857.
> 
> Nikita
