PHP: Trying to fix the fractal


  • BINNED

    I saw this on reddit today. Apparently, trying to fix the "fractal of bad design" that is PHP annoys users who have come to depend on the brokenness.



  • It's the things that are not broken in PHP that are the most annoying, such as the notations for foreach and for adding items to an array:

    foreach ($array1 as $item) {
        $array2[] = $item;
    }
    

    I've shown this to my niece and she cried. Now I cannot got to her first communion.

    Note to PHP afficionados: this sample code is there to show the unpleasant notation, not a design pattern.



  •  How is that cry-worthy notation?

    PHP's shitty object model means arrays don't have a push() method,but I really don't find any fault with empty brackets.



  • @dhromed said:

     How is that cry-worthy notation?

    PHP's shitty object model means arrays don't have a push() method,but I really don't find any fault with empty brackets.

    ARE YOU CALLING MY NIECE A SISSY????

    Seriously I don't find that push notation intuitive. Something like this would have been more natural IMHO:

    $array += $item;
    

    With or without brackets.



  • @PedanticCurmudgeon said:

    I saw this on reddit today. Apparently, trying to fix the "fractal of bad design" that is PHP annoys users who have come to depend on the brokenness.
     

    I think my favorite part was the request (to Rasmus himself) to "Please escalate this to someone who can answer the question as to why this was changed."



  • @endosquid said:

    Dramatic? You've obviously never worked in a change-request-release environment. We have number_format in literally thousands of places across 50 or 60 separate products. Each of those changes will have to be coded, tested, written-off, released, tested by the clients since this is tax data and has to be precise for tax planning and retirement planning.

    Most frightening part of the discussion.

    First I was like, "you're using that poorly-specced function for formatting TAX data?

    Then I was like, "you're getting TAX data in which something that's nominally a number can sometimes be sent strings or other data types?"

    Then I was like, "you're using PHP to do anything in relation to TAX data?"



  • I find it curious that the person stating "Dramatic? You've obviously never worked in a change-request-release environment." is moaning about how much time and effort this will require... when changing PHP version.

    It's not like they've been forced to upgrade... have they?

    And yup, TRWTF is relying on the brokeness. Although I can understand how the situation arose.

     



  • Yea... using php to handle tax data bright move there.  IMO if you call a number format on an item that cant be formated like a null or empty string, it should neither return 0 or null it should throw an exception.  I am a little surprised that it does not.


  • BINNED

    @Anketam said:

    Yea... using php to handle tax data bright move there.  IMO if you call a number format on an item that cant be formated like a null or empty string, it should neither return 0 or null it should throw an exception.  I am a little surprised that it does not.

    After reading the "fractal of bad design" article, I'm no longer surprised by any WTFness in PHP.


  • Discourse touched me in a no-no place

    @Anketam said:

    Yea... using php to handle tax data bright move there.
    Bollocks. The complainer was, from what was posted, passing un-santitised data to a function that wasn't designed to handle out-of-bounds data. For those using C, it's like passing -1 to close(2) - something I've had reason to sort out recently.



  • I don't know. I'd be pissed if my underlying platform suddenly started returning NULLs when it never did before. That's a change of behavior. Still, when it happens, it's your job to fix it in your application. I don't think that the guy submitting the bug was entirely wrong to reporting a change in behavior between releases as a bug.



  • LOL! Food fight in the bug report!

    @dhromed said:

    PHP's shitty object model means arrays don't have a push() method,but I really don't find any fault with empty brackets.

     

     There is a push function. And an amusing note about the "overhead" of using a function when you're pushing one item.

     http://jp2.php.net/manual/en/function.array-push.php

    C'mon ... I worry about overhead when I'm pushing thousands or millions of items.

     



  • @Speakerphone Dude said:

    ...

    Seriously I don't find that push notation intuitive. Something like this would have been more natural IMHO:

    $array += $item;
    

    With or without brackets.


    I don't find that using intuition is the best way to get code working.

    I'm sorry but I just don't like looking at:

    $stuff += $things;

    and wondering what operation += is doing. Adding? Concatenating strings? Pushing? Registering something? Oh right I have to go parse for context. Thanks. Or maybe I should use intuition?

     



  • @superjer said:

    @Speakerphone Dude said:

    ...

    Seriously I don't find that push notation intuitive. Something like this would have been more natural IMHO:

    $array += $item;
    

    With or without brackets.


    I don't find that using intuition is the best way to get code working.

    I'm sorry but I just don't like looking at:

    $stuff += $things;

    and wondering what operation += is doing. Adding? Concatenating strings? Pushing? Registering something? Oh right I have to go parse for context. Thanks. Or maybe I should use intuition?

     

     

    The += operator isn't the problem (we had something like it in SAS).  It's the absence of brackets or any other indication that you're dealing with an array rather than a scalar.  I had enough of that back when I did APL.

     



  • @superjer said:

    I'm sorry but I just don't like looking at:

    $stuff += $things;

    and wondering what operation += is doing.

    so you prefer looking at

    $stuff[] = $things;
    

    because it is sooooooooooooo obvious that it's adding to the array, not replacing it?



  • @Speakerphone Dude said:

    Seriously I don't find that push notation intuitive. Something like this would have been more natural IMHO:

    $array += $item;
    

    With or without brackets.

     

    Sorry, that notation is already used for concatenating arrays.

     @Speakerphone Dude said:


    because it is sooooooooooooo obvious that it's adding to the array, not replacing it?

    What, you mean in the same way that

    $array[42] = $item;
    
    modifies the array instead of replacing it?


  • @Watson said:

    What, you mean in the same way that

    $array[42] = $item;
    modifies the array instead of replacing it?

    No. I've seen the array[index] = value notation in many programming languages, this is typical. But array[] = value to add a value to the array is something I've never seen outside PHP. Maybe this is why I find it less intuitive. But I haven't used that many different languages, so for my benefit maybe you can name one other language where this empty bracket notation is used for adding items?



  • @Speakerphone Dude said:

    so you prefer looking at

    $stuff[] = $things;
    

    because it is sooooooooooooo obvious that it's adding to the array, not replacing it?

    I prefer it because it looks different from $number += $number2 and $string += string2.

    $stuff->append($things) would be what I would call obvious. But that's also wordy.

    I can accept wordy. I can accept unobvious. I don't like ambiguous.

     



  • @superjer said:

    I can accept wordy. I can accept unobvious. I don't like ambiguous.

    I still dislike the empty bracket notation (as well as the foreach notation) but it's hard to disagree with your point.



  • @Speakerphone Dude said:

    @Watson said:

    What, you mean in the same way that

    $array[42] = $item;
    

    modifies the array instead of replacing it?

    No. I've seen the array[index] = value notation in many programming languages, this is typical. But array[] = value to add a value to the array is something I've never seen outside PHP. Maybe this is why I find it less intuitive. But I haven't used that many different languages, so for my benefit maybe you can name one other language where this empty bracket notation is used for adding items?

     

    Irrelevant, really; it's PHP, not <insert arbitrary language here>. That said, I'm having trouble thinking of a language that has a distinct notation for appending an element to an existing array; certainly you won't find one in any language where arrays are always of fixed length.

    But if you're going to judge the syntax of one language by how much or how little it resembles some other language then your own preference isn't very well thought out:

    $array += $item;

    If "+=" has the same meaning that it it has in languages with syntaxes derived from C (including PHP) then you'd expect that line to be pretty much equivalent to:

    $array = $array + $item; 

    So you need to define what $array + $item means.

     

    Plus, you're being disingenuous:  "I've seen the array[index] = value notation in many programming languages" [those with syntaxes derived from Algol via C] ... "I haven't used that many different languages". Of course, I've seen (and used) a number of languages that don't use array[index] = value. I don't see that as any sort of WTF; if I choose to use language Foo instead of language Bar, whose fault is that, and who should I complain to when I find that language Foo isn't the same as language Bar?

     @Speakerphone Dude said:

    (as well as the foreach notation)
    And what precisely is your problem with foreach's syntax? Before replying, consider that the syntaxes used in Java and C# are (a) for statically-typed languages and so need support for declaring the element type, while PHP doesn't do static typing; and (b) were added to those languages after the construct was already present in PHP.

     

    Really, if those are the sort of things that give you grief, you should stay away from PHP, lest you have to deal with any of PHP's real syntactical problems.



  • @Watson said:

    And what precisely is your problem with foreach's syntax? Before replying, consider that the syntaxes used in Java and C# ... (b) were added to those languages after the construct was already present in PHP.


    When they were showing around early previews of Java 5 I asked for a foreach over Maps completely unaware that PHP had it. That aspect of PHP's foreach is clearly far more convenient than Java's or C#'s:

    foreach ($dict as $key => $val) {
        ...
    }
    
    for (Map.Entry<K, V> e : map) {
        K key = e.getKey();
        V val = e.getValue();
        ...
    }
    
    foreach (KeyValuePair<K, V> kvp in dict) {
        K key = kvp.Key;
        V val = kvp.Value;
        ...
    }

    Only the PHP version allows you to give meaningful names to the key and value concisely.



  • @superjer said:

    I can accept wordy. I can accept unobvious. I don't like ambiguous.

    yup + yup + comments.

    I don't like the latter either, but ever since I became conversant[1] in several different languages I've relied upon comments to summarise the operation so I don't need to remember syntax context.

    [1] FSVO "conversant". Still JoAT at most.



  • @Cassidy said:

    I've relied upon comments to summarise the operation so I don't need to remember syntax context.

    $array[]] = $item; // add item to array
    


  • @pjt33 said:

    for (Map.Entry<K, V> e : map) {
        K key = e.getKey();
        V val = e.getValue();
        ...
    }
     
    Even worse, in java you have to do map.entrySet(). I am really annoyed that there is no notation similar to PHP in Java. It's really convenient. 

     



  • @pbean said:

    Even worse, in java you have to do map.entrySet().

    Oops. Yes, indeed. You can tell I don't do much Java at the moment.



  • @spamcourt said:

    @Cassidy said:

    I've relied upon comments to summarise the operation so I don't need to remember syntax context.

    $array[] = $item; // add item to array
    

    Yeah.... perhaps I should expand: I would have expected to see a comment of "add this item to the current shopping basket" or "now include chosen meal to the order", but that functional description would have sufficed. At least it tells me it's a "push" operation.



  • @Watson said:

    And what precisely is your problem with foreach's syntax?

    I know that PHP and Python have the same kind of notation for foreach, and it happens to be reversed compared to C#, Java or VB. But it's not related to typing, because Powershell (which is also a scripting language) uses the same notation as C#, Java and VB. So I don't know why somebody decided to use a reversed notation, all I know is that when you switch frequently from most languages to PHP this kind of thing is annoying. It would not have been that much more difficult to just use a item in list notation, it feels like a random decision.



  • @Speakerphone Dude said:

    I know that PHP and Python have the same kind of notation for foreach, and it happens to be reversed compared to C#, Java or VB.

    Check again. The Python version of your original example would be:

    for item in array1:
       array2.append(item)


    It has the same order as C# and Java, and is IMO more readable than either.



  • @Speakerphone Dude said:

    It would not have been that much more difficult to just use a item in list notation, it feels like a random decision.


    So the developers of PHP should have foreseen that in the future other languages will mimic the foreach notation using another order of parameters and should have used that order instead?



    /facepalm



  • What julmu said. You should have taken my advice: @Watson said:

    Before replying, consider that the syntaxes used in Java and C#  ... were added to those languages after the construct was already present in PHP. 

     @Speakerphone Dude said:

    "I've seen the array[index] = value notation in many programming languages"

    I'm still having trouble finding a language with a distinct syntax for appending an array element; the closest was bash, but even that was just using syntax that already existed for other purposes. On the other hand, I made a short list of some of the array element assignment syntaxes I've used over the years and still have on immediate recall:

    arr[n] = item;
    

    arr(n) = item

    arr[[n]] = item
    Set[Part[arr, n], item]

    arr n item put

    (vector-set! arr n item)

    arr // [(n,item)]

    -=[arr] item,n



  •  Oh, of course. There's prepending an item to an array (rather, a list):

    item : array
    But that's in a functional language, so instead of changing the array it returns a new one.


  • @Watson said:

    I made a short list of some of the array element assignment syntaxes I've used over the years and still have on immediate recall:

    arr[n] = item;
    

    arr(n) = item

    arr[[n]] = item
    Set[Part[arr, n], item]

    arr n item put

    (vector-set! arr n item)

    arr // [(n,item)]

    -=[arr] item,n

    You must not have worked with Rexx, where it's:

     

    arr.n = item

     

     



  • @da Doctah said:

    You must not have worked with Rexx, where it's:

     

    arr.n = item

     

     

    You're right, I haven't. By no coincidence at all I was just thinking about taking another look at it (all I remembered about my last look was that the language [i]existed[/i], which is nowhere near enough). Can't tell which distro would be best to start with, but I am finding an odd tendency for the web sites to look like something hosted by Geocities.

     



  • I use PHP daily. I would like to point out that

    $array2[] = $item;
    is exactly equivalent to
    $array2[ count( $array2 ) ] = $item;
    So why did someone invent a unique language syntax for a statement that can already be expressed adequately in that language?



  • @AndyCanfield said:

    I use PHP daily. I would like to point out that

    $array2[ = $item;
    is exactly equivalent to
    $array2[ count( $array2 ) ] = $item;

    So why did someone invent a unique language syntax for a statement that can already be expressed adequately in that language?

     

    Because, unfortunately, they're not exactly equivalent (exercise for the reader).

     

     

     



  • @Mason Wheeler said:

    @PedanticCurmudgeon said:

    I saw this on reddit today. Apparently, trying to fix the "fractal of bad design" that is PHP annoys users who have come to depend on the brokenness.
     

    I think my favorite part was the request (to Rasmus himself) to "Please escalate this to someone who can answer the question as to why this was changed."

    Rasmus has escalated the issue to God and the issue is now being resolved.

     



  • @AndyCanfield said:

    So why did someone invent a unique language syntax for a statement that can already be expressed adequately in that language?

    Have you ever used a language which has both for and while loops? With the exception of Turing tarpits, very few languages are completely devoid of syntax sugar.


  • Considered Harmful

    @pjt33 said:

    foreach (KeyValuePair<K, V> kvp in dict) {
    K key = kvp.Key;
    V val = kvp.Value;
    ...
    }

    Only the PHP version allows you to give meaningful names to the key and value concisely.



    foreach( var key in dict.Keys ) {
    var val = dict[ key ];
    }

    A little more succinct.



  • @joe.edwards said:

    foreach( var key in dict.Keys ) {
    var val = dict[ key ];
    }

    A little more succinct.

    But almost certainly inefficient - it multiplies the cost of iterating through the map by the cost of a lookup in the map.

  • Considered Harmful

    @pjt33 said:

    But almost certainly inefficient - it multiplies the cost of iterating through the map by the cost of a lookup in the map.

    True. I usually deal with dictionaries with about 12 items or less (the express lane of dictionaries), so the big-O cost is usually not very important.



  • @Watson said:

    @AndyCanfield said:

    I use PHP daily. I would like to point out that

    $array2[ = $item;
    is exactly equivalent to
    $array2[ count( $array2 ) ] = $item;

    So why did someone invent a unique language syntax for a statement that can already be expressed adequately in that language?

     

    Because, unfortunately, they're not exactly equivalent (exercise for the reader).

     

     

    From the PHP manual: "An array in PHP is actually an ordered map." What that means is that this:

    [code]
    $my_array = array( 1 => true);
    $my_array[ count( $my_array ) ] = $item;
    [/code]

    Is not the same as this:

    [code]
    $my_array = array( 1 => true);
    $my_array[ ] = $item;
    [/code]

    Andy, are you one of those people who use PHP daily but never look at the manual?


  • Considered Harmful

    @toon said:

    From the PHP manual: "An array in PHP is actually an ordered map." What that means is that this:

    Does that mean an array can have gaps in it? Like you can define $arr[1] and $arr[3] without defining $arr[2] (breaking Andy's push implementation in the process)?

    Just when I thought my opinion of a language couldn't sink much lower...



  • @joe.edwards said:

    @toon said:
    From the PHP manual: "An array in PHP is actually an ordered map." What that means is that this:

    Does that mean an array can have gaps in it? Like you can define $arr[1] and $arr[3] without defining $arr[2] (breaking Andy's push implementation in the process)?

    Just when I thought my opinion of a language couldn't sink much lower...

    Yes, in PHP an array can have gaps in it, but you can make arrays behave more like C or Java arrays if you want, by writing your code appropriately. However, the weird gap thing can actually be quite helpful, since you can have strings as keys if you want. That can come in quite handy. On the other hand, maybe a separate dictionary type like they have in Python might be better.



  • @joe.edwards said:

    Does that mean an array can have gaps in it? Like you can define $arr[1] and $arr[3] without defining $arr[2] (breaking Andy's push implementation in the process)?

    Just when I thought my opinion of a language couldn't sink much lower...

    So what should $arr[2] be defined to contain then? FILE_NOT_FOUND?


    @toon said:

    On the other hand, maybe a separate dictionary type like they have in Python might be better.
    Don't forget to include all the necessary support for mapping between the different types.

     


  • Considered Harmful

    My issue with this comes down to calling any ordered set an array. I'd expect an array to have a lower and an upper boundary, with all contiguous values between those values defined. If 1 is a valid index and 3 is a valid index, how can 2 be out of bounds? It seems to be in violation of a very common contract that is implied when calling something an array. It's another gotcha in a language that sounds like a minefield of little quirks like this.

    If I was a PHP developer I'd be expected to know all the ins and outs of the language, but with all I've read here about it (weirdness in typecasting/coercion, inconsistent API conventions, GPC magic quotes, variable variables[really?], register globals...) I just thank my lucky stars that I get to work with sane languages.



  • @joe.edwards said:

    My issue with this comes down to calling any ordered set an array. I'd expect an array to have a lower and an upper boundary, with all contiguous values between those values defined.

    I guess I'm a bit more forgiving about what terms are used provided those terms are adequately defined. Maybe that's because my background is mathematics (where things mean only what they are defined to mean), and because my relationship with programming languages tends to be on the, ah, promiscuous side (so I don't just assume I already know what something means). toon quoted the very first sentence in the PHP manual's page on arrays, so I never had the expectation you have. In fact, the whole paragraph reads: @The PHP manual said:
    An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays, trees and multidimensional arrays are also possible.

    So the only people with any excuse for not expecting that the existence of $a[1] and $a[3] doesn't imply the existence of $a[2] are people who don't know what they are talking about. Maybe the word "map" should have been used throughout the language instead of "array" - but that wouldn't change the language in any significant way, only the prior expectations of people who haven't used it.

    @joe.edwards said:

    If 1 is a valid index and 3 is a valid index, how can 2 be out of bounds?

    $words = ['An', 'ordinary', 'list', 'of', 'words', 'with', 'varying', 'lengths'];
    $longer_words = array_filter($words, function($word)
    {
        return strlen($word) > 5;
    });
    

    The keys of $words are 0 to 7 inclusive; what should the keys of $longer_words be (in PHP, they're 1, 6, and 7)?

    @joe.edwards said:

    I'd expect an array to have a lower and an upper boundary, with all contiguous values between those values defined.
    PHP has such things as well.They're not used as much because they're newer and less widely applicable, so fewer people know about them and fewer still use them (the only reason you'd use fixed arrays instead of ordinary ones (assuming they're applicable) is if you had a particular need for getting the speed up or memory footprint down at that point). Then again, if all you want to ensure that a given (ordinary) array has values for all keys in a specific (numeric) range, you'd just initialise it appropriately: array_fill($lower_bound, $length, $default_value).

    @joe.edwards said:

    (weirdness in typecasting/coercion, inconsistent API conventions, GPC magic quotes, variable variables[really?], register globals...)
    Type casting isn't that much weirder than in other loosely-typed languages that do automatic coercion (it typically bites people who don't know how it works and think any coercion is a one-step process); inconsistent API conventions are a pain and I usually end up writing my own wrappers; GPC magic quotes are dead; variable variables are evil and I keep a special selection of severe beatings on hand for anyone on my teams who tries to use them (they're top of my list of things in PHP that must die - who thought importing the idea from bash scripting would be a good idea?); register globals has been dead for years.

    What I find are the worst aspects (apart from the way it attracts the clueless like nekkid wimmin attract males) are the manky handling of function and method names, the inadequate namespacing thereof that (among other things) throttles calling methods defined at run time, inadequate call dereferencing, and ...

    Oh, yes: the fact that the only formal language specification in existence is the yacc source file. Yup, the only arbiter of what qualifies as a syntactically valid program is the parser itself, and the parse tree it generates for even the simplest code fragment is a ghastly long-winded mess even before the additional fiddling that happens in the action handlers.



  • @superjer said:

    I don't find that using intuition is the best way to get code working.
     

    Nothing wrong with Intuition.

     



  • @joe.edwards said:

    My issue with this comes down to calling any ordered set an array. I'd expect an array to have a lower and an upper boundary, with all contiguous values between those values defined..

    Not an ordered set! Those don't exist. An ordered map. There's a definite difference. Also, why should all the values in arrays be contiguous? I can't have an array with the ints 3, 5, and 7 in it? What happens if I want an array with floats in it, hmm? Also, any array in PHP has a finite number of elements. It's impossible for such a thing to lack bounds.

    @joe.edwards said:

    If 1 is a valid index and 3 is a valid index, how can 2 be out of bounds?

    Not "out of bounds". That's a C error message. Whole different ballpark! The term PHP uses is undefined. Again, not the same thing.

    @joe.edwards said:

    [...]It's another gotcha in a language that sounds like a minefield of little quirks like this.

    If I was a PHP developer I'd be expected to know all the ins and outs of the language, but with all I've read here about it (weirdness in typecasting/coercion, inconsistent API conventions, GPC magic quotes, variable variables[really?], register globals...) I just thank my lucky stars that I get to work with sane languages.

    The API thing sucks. Typecasting? PHP is weakly typed. Any PHP developer knows that. If your PHP code relies on typecasting or type coercion, you're writing bad PHP. Not that I don't wish PHP were strongly typed, I'm just saying it isn't and any PHP professional needs to realize that. GPC magic quotes can be a bummer. Certain Linux servers available for download today still have this on by default. They did away with that in 5.4 though. Register_globals has not been an issue since PHP 5 (which was ages and ages ago). Variable variables... Well I agree with everyone else on that one.



  •  Thinking about this a bit, I can see the user's point, although he's not making it very well. In certain contexts –for example, when filling in a tax form– it does actually make sense to consider an empty string as 0. The mistake that the user makes is to assume that it makes sense in all cases, and failing to see that his code relies on a bug, rather than a feature.

    TRWTF is that it took the PHP authors 15 years to take care of that bug.



  • @Watson said:

    @The PHP manual said:
    An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more.
    So the only people with any excuse for not expecting that the existence of $a[1] and $a[3] doesn't imply the existence of $a[2] are people who don't know what they are talking about.
    The PHP manual explicitly states - in the very part that you quoted - or at least very strongly suggests that PHP-arrays can be treated just like a (common) array, which would make most coders coming from other languages expect that it should behave just as joe.edwads described - but it doesn't.

    That's like a car company telling people that their new model works "just like any other car", but forgetting to mention that it is actually a tricycle, because they left out the wheel on the front right, which means that it might tip over when you've got a fat guy in the passenger seat...

     


Log in to reply