php bug of mijn fout???

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Jan R

Jan R

29/10/2019 12:53:57
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
$a = array(1,2,3,4,5,6);
foreach ($a as &$b) {
 $b *=2;
}

foreach ($a as $b) {
 echo $b . '<br>';
}


output
2
4
6
8
10
10

verwacht
2
4
6
8
10
12

Waarom heb ik 2X 10 en niet 10 en 12
Doe ik iets fout of is dit een bug

Jan
Gewijzigd op 29/10/2019 13:16:25 door - Ariën -
 
PHP hulp

PHP hulp

19/04/2024 20:41:08
 
Zwolly Wood

Zwolly Wood

29/10/2019 14:00:04
Quote Anchor link
Hallo Jan,

Ik kom er ook niet uit;

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php

$a
= array(1,2,3,4,5,6,7,8);
foreach ($a as &$b) {
 $b = $b*2;
}


foreach ($a as $b) {
 echo $b . '<br>';
}


?>


Zoals ik het begrijp gaat alleen de laatste berekening niet goed.

Dit is mijn output

2
4
6
8
10
12
14
14
Gewijzigd op 29/10/2019 14:00:48 door Zwolly Wood
 
- Ariën  -
Beheerder

- Ariën -

29/10/2019 14:01:37
Quote Anchor link
Ik vind het ook frappant :-P
Het speelt wel in alle versies van PHP, dus het is geen tussentijdse bug.
 
Jan R

Jan R

29/10/2019 14:08:29
Quote Anchor link
YES!

Ik heb een bug gevonden :)
Na 10tallen in Excel en Windows nu eentje in php

Toevoeging op 29/10/2019 14:08:55:

Hoe kunnen we dit doorspelen?
 
- Ariën  -
Beheerder

- Ariën -

29/10/2019 16:10:33
Quote Anchor link
Gebeurt dit enkel op Linux, of heeft dit op Windows andere uitwerkingen?
Just interesting. Ik heb het ook even voorgelegd aan Tweakers. Toch benieuwd hoe dit zit. Op Linux speelt dit wel onder alle versies, waaronder de EOL.

Update: Ook op Windows speelt het.
"$b blijft een referentie naar het laatste element uit de eerste loop." zegt iemand daar.

unset($b); na je eerste foreach zou moeten helpen.

Toch zijn hulplijntjes wel eens handig :P
En ja, PHP blijft een 'dumb programmer language'
Gewijzigd op 29/10/2019 16:23:37 door - Ariën -
 
Thomas van den Heuvel

Thomas van den Heuvel

29/10/2019 17:01:20
Quote Anchor link
Wat je hier allemaal aan het doen bent is toch redelijk onorthodox. Je gebruikt hier call-by-reference op $b. En dan worden van arrays pas kopieën gemaakt als hier waarden in worden gewijzigd. Je hebt geen enkel idee van wat dit onder water voor effect heeft qua geheugenreferenties en waarden. Het is een aanpak waarbij je een heleboel zaken niet ziet. Simpelweg omdat je niet begrijpt wat er gebeurt maakt iets nog niet fout. Je moet je afvragen of het gebruik van een & hier wel verstandig is (waarschijnlijk niet). Er zijn immers legio manieren om dit op een manier te doen waarbij het effect makkelijker te doorgronden is.

Dit werkt altijd, en maakt wat mij betreft expliciet duidelijk wat de bedoeling is:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
foreach ($a as $index => $dummy) {
    $a[$index] *= 2;
}

?>

Een callback- of lambda-functie doet het ook prima:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$a
= array_map(function($in) { return $in * 2; }, $a);
?>


Daarbij, als je dan toch volhardt in een aanpak met een referentie, dan loont het op zijn minst de moeite om er in commentaar bij te vermelden wat het eigenlijk zou moeten doen. Als dit dan niet voldoet aan de specificatie, dan weet je op zijn minst hoe je dit moet veranderen. Dit verdient ook in algemene zin de voorkeur. Het kan je later helpen om de draad weer op te pakken als je de code een tijd niet gezien hebt.

Het probleem is dus overigens niet $a. De waarden in $a bevatten na afloop van de eerste foreach-loop de correcte waarden. Het is die $b, die je gebruikt om in de tweede loop $a te dumpen. Die, zoals in die Tweakers discussie wordt aangehaald, blijft bestaan buiten de scope van de eerste foreach-loop. Niet helemaal netjes, maar soit. Op het moment dat je referenties gaat gebruiken moet je gewoon héél erg goed opletten.

Als je het volgende doet dan geeft dit gewoon het gewenste resultaat:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
$a
= array(1,2,3,4,5,6);
foreach ($a as &$b) {
    $b *=2;
}

echo '<pre>'.print_r($a, true).'</pre>';
?>


- Ariën - op 29/10/2019 16:10:33:
En ja, PHP blijft een 'dumb programmer language'

Nou nee, het zijn toch voornamelijk dumb programmers. PHP heeft nou eenmaal een aantal quirks en is ook heel laagdrempelig en accepteert veel, heel veel. Daarom is het zaak dat dit gecompenseerd wordt door enige programmeerdiscipline die menig (beginnend) "programmeur" gewoon (nog) niet heeft.

Ik zou gewoon wegsturen van een oplossing met referenties als je deze niet nodig hebt. Omdat dit dus onvoorziene consequenties kan hebben maar ook omdat er gewoon andere constructies zijn die veel transparanter zijn dan wat hier gebeurt.
Gewijzigd op 29/10/2019 17:06:13 door Thomas van den Heuvel
 
Rob Doemaarwat

Rob Doemaarwat

29/10/2019 18:58:09
Quote Anchor link
Gewoon aanleren om na een foreach() met een referentie altijd een unset() te doen (net zoals na een haakje openen een haakje sluiten komt).
 
Thomas van den Heuvel

Thomas van den Heuvel

29/10/2019 19:32:08
Quote Anchor link
Of gewoon geen referenties gebruiken als je dit kunt vermijden.
 
H Kse

H Kse

29/10/2019 19:59:39
Quote Anchor link
Ik denk dat het iets te maken heeft omdat je &$b gebruikt in je eerste foreach want als je m als $c gebruikt werkt deze wel.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php

$a
= array(1,2,3,4,5,6);
foreach ($a as &$b) {
 $b *=2;
}


foreach ($a as $c) {
 echo $c . '<br>';
}
Gewijzigd op 29/10/2019 20:00:46 door H Kse
 
Thomas van den Heuvel

Thomas van den Heuvel

29/10/2019 20:33:32
Quote Anchor link
Dat kan ook, maar het lijkt mij beter om deze hele constructie met & in eerste intantie te vermijden.
Gewijzigd op 29/10/2019 20:33:59 door Thomas van den Heuvel
 
Jan R

Jan R

30/10/2019 09:18:49
Quote Anchor link
Thomas van den Heuvel op 29/10/2019 17:01:20:
Wat je hier allemaal aan het doen bent is toch redelijk onorthodox.


Je hebt ABSOLUUT gelijk :)

Dit was slechts een testje. Ik wist dat de ampersand werkte in functies. Ik wist echter niet dat dit kon in een foreach en plots kwam ik dit tegen in een ander topic.

Mijn bedoeling was dus ook om gewoon even te testen hoe dit werkte. Niet om te gebruiken. Normaal werk ik dus ook met de key over de echte array.

Soms zijn het de stomme testjes, of programmeurs, die fouten vinden.

Volgens mij is het sowieso een bug.

Toch allen bedankt voor de input en het mee testen.
Jan
 
- Ariën  -
Beheerder

- Ariën -

30/10/2019 09:25:06
Quote Anchor link
Jan R op 30/10/2019 09:18:49:

Volgens mij is het sowieso een bug.

Lees het gelinkte topic naar Tweakers eens? ;-)
 
Ivo P

Ivo P

31/10/2019 14:10:10
Quote Anchor link
ik verwacht dat duidelijk wordt wat er gebeurt, als je in de 2e loop ook steeds $a dumpt:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php

$a
= array(1,2,3,4,5,6);
foreach ($a as &$b) {
 $b *=2;
}


foreach ($a as $b) {
 echo $b . PHP_EOL;
 var_dump($a);
}

 ?>


je krijgt dan
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
array(6) {
  [0]=>
  int(2)
  [1]=>
  int(4)
  [2]=>
  int(6)
  [3]=>
  int(8)
  [4]=>
  int(10)
  [5]=>
  &int(2)
}
4
array(6) {
  [0]=>
  int(2)
  [1]=>
  int(4)
  [2]=>
  int(6)
  [3]=>
  int(8)
  [4]=>
  int(10)
  [5]=>
  &int(4)
}

etc

je ziet dat het laatste element steeds vervangen wordt door de nieuwe waarde die in $b geplaatst wordt.
Zie ook de & voor int.

Toevoeging op 31/10/2019 14:11:03:

conclusie: vermijd by-reference als het niet per se nodig is.
Gewijzigd op 01/11/2019 10:49:55 door Ivo P
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.