PHP foreach WTF



  • [code]
    foreach($foo as $something => $bar) {
    
        // ...snip 6 lines
    
        foreach($bar as $blah => $foo) {
           // ...snip
        }
    
        // ...snip
    
    }
    [/code]

    TRWTF is, this code apparently seems to always have worked fine.

    edit: the $foo is only used in the inner foreach loop, I am now noticing. Still, this can't be right.



  •  I could be wrong but it acts like a local varible so the first $foo will be reached from the inner loop



  • Thanks to the joys that is PHPs shitty excuse for scoping, that is a very good Heisenbug.



  • @Cratig said:

     I could be wrong but it acts like a local varible so the first $foo will be reached from the inner loop

    Yeah, that's what I meant by "the $foo is only used in the inner foreach loop", as opposed to the outer one too, or after the inner foreach loop ends. That explains why that code seemed to always have worked.



  • This works because foreach creates a copy of the array before iterating on it.



  • @henke37 said:

    This works because foreach creates a copy of the array before iterating on it.

    If PHP is your career, please consider reading a book or two, or choosing a different path for yourself.

    It works, because no code refers to [code]$foo[/code] after the inner [code]foreach[/code] loop exits (edit: and inside the outer [code]foreach[/code] loop). I'm quite positive that [code]$foo[/code] gets mangled up because of that inner loop; give it a test for yourself.



  • @toon said:

    It works, because no code refers to <font face="Lucida Console" size="2">$foo</font> after the inner <font face="Lucida Console" size="2">foreach</font> loop exits (edit: and inside the outer <font face="Lucida Console" size="2">foreach</font> loop). I'm quite positive that <font face="Lucida Console" size="2">$foo</font> gets mangled up because of that inner loop; give it a test for yourself.

    Well, the name $foo gets rebound to whatever value is set in the inner loop. The array $foo points to is fine--you can verify this by creating a second reference to it before the first foreach and then accessing it after.


  • 🚽 Regular

    Toon is most definitely right. Most languages would consider this a compiler warning at best. It might still invoke an E_STRICT level warning in PHP, but I'm not sure. Once someone wants to do something with the "outer" $foo after the loop, and doesn't follow the code carefully before doing so, that dev will probably investigate the ensuing error, followed by facepalming.



  • @henke37 said:

    This works because foreach creates a copy of the array before iterating on it.

    I don't think that's true at all.

    First off, it works because the outer foreach resolves $foo at the start; it's not dereferencing the name on each iteration, it's just operating on the array the reference points to.

    The value of the array $foo points to isn't being modified, so copy-on-write should not apply. However, if the array was passed into this function by value, it's possible the hash table was copied, but the copied hash table would share values with the old hash table.



  • @RHuckster said:

    Most languages would consider this a compiler warning at best.

    You sure about that? I'm too lazy to check, but I'm pretty sure Java lets you shadow variables with impunity (although the semantics are different from PHP--the inner scope always takes precedence). It seems like something I should know, but since I would never do something this dumb I guess I've never run into it.

    @RHuckster said:

    It might still invoke an E_STRICT level warning in PHP, but I'm not sure.

    Not on 5.3.5.



  • @morbiuswilters said:

    @RHuckster said:
    Most languages would consider this a compiler warning at best.

    You sure about that? I'm too lazy to check, but I'm pretty sure Java lets you shadow variables with impunity (although the semantics are different from PHP--the inner scope always takes precedence). It seems like something I should know, but since I would never do something this dumb I guess I've never run into it.

    @RHuckster said:

    It might still invoke an E_STRICT level warning in PHP, but I'm not sure.

    Not on 5.3.5.

    This would be an outright error in C#, if the outer variable is a local variable. If it's a class member, then it's fine.


  • Discourse touched me in a no-no place

    @morbiuswilters said:

    @RHuckster said:
    Most languages would consider this a compiler warning at best.

    You sure about that? I'm too lazy to check, but I'm pretty sure Java lets you shadow variables with impunity (although the semantics are different from PHP--the inner scope always takes precedence).

    gcc (and probably other C and C++ compilers) can be made to warn about it, but it's not a requirement of The Standard.



  • @pkmnfrk said:

    This would be an outright error in C#, if the outer variable is a local variable. If it's a class member, then it's fine.

    Personally, I think it should always be an error. Variable shadowing is lame.



  • @morbiuswilters said:

    @pkmnfrk said:
    This would be an outright error in C#, if the outer variable is a local variable. If it's a class member, then it's fine.

    Personally, I think it should always be an error. Variable shadowing is lame.

    I suspect it has more to do with mitigating situations where Joe Q. Doesntknowprogramming breaks the build by adding i as a class-member.

    Of course it's entirely moot since best-practises don't allow for any shadowing at all; class-level members get an Upper-case initial letter, while locals get lower-case.



  • @pkmnfrk said:

    I suspect it has more to do with mitigating situations where Joe Q. Doesntknowprogramming breaks the build by adding i as a class-member.

    Why not just make that an error? "Hey, fuckface, there's already a local variable called 'i'. Also, 'i' is an awful name for an instance variable. As punishment, I have deleted all of your important files and emailed child pornography to the FBI from your email address."



  • @morbiuswilters said:

    [java vs php semantics] It seems like something I should know, but since I would never do something this dumb I guess I've never run into it.

    That is a very good point that I learned a long time ago. If you want to do something where pedantic dickweedy programming language details really matter, you're better off adding a few parentheses or rewriting a loop. Even if that makes it less "elegant". If nothing else, you hugely improve legibility. Not that pedantic detailed technical stuff isn't important in knowing a language, I think it is. But if when thinking about what a few lines of code are going to do, depends on a technical detail only really pedantic dickweeds know, you're doing something wrong. I may be wrong, but I think that's sort of what you mean there.

    Of course, before anyone makes the point, I am assuming that wasting a CPU cycle or two is not the end of the world; but then again we are talking about PHP here and not about writing assembly language for devices that can't divide because they only have 5 different instructions, 2 registers and 3 bytes of RAM.



  • @toon said:

    That is a very good point that I learned a long time ago. If you want to do something where pedantic dickweedy programming language details really matter, you're better off adding a few parentheses or rewriting a loop. Even if that makes it less "elegant". If nothing else, you hugely improve legibility. Not that pedantic detailed technical stuff isn't important in knowing a language, I think it is. But if when thinking about what a few lines of code are going to do, depends on a technical detail only really pedantic dickweeds know, you're doing something wrong. I may be wrong, but I think that's sort of what you mean there.

    Agreed. If you need to know how your language handles variable shadowing, you are probably doing something dumb.

    @toon said:

    ...devices that can't divide because they only have 5 different instructions, 2 registers and 3 bytes of RAM.

    And have to add uphill through the snow, both ways.



  • @morbiuswilters said:

    Hey, fuckface
     

    That's excellent. From now on I'm starting all error messages with "Hey, fuckface!"



  • @oheso said:

    @morbiuswilters said:

    Hey, fuckface
     

    That's excellent. From now on I'm starting all error messages with "Hey, fuckface!"

    Hey, fuckface! YA DUN GOOFED!



  • Run it, it doesn't output any SURE lines.



  • Let's talk about rezzing now.


  • Trolleybus Mechanic

    @Xyro said:

    Let's talk about rezzing now.
     

    Hey, fuckface! I [b]de[/b]rezz you!




  •  Sooo... this code is a less of a WTF than the front-page article?

    I guess slightly since it's not remapping $foo/$cat in the original foreach line.


Log in to reply