An interesting php snippet



  • I just found the following code in some code i am bugfixing(Aka rewriting)

    if($endtime == 00) {
      $endtime = 0;
    }

    The code had a comment, saying that it was removing the extra 0 if it was there. ($endTime is a string)

    The funny thing about this code is that it actuelly DOES work, and for all practical purposes does what the original author intended

    (That is transform the string "00" to "0") but the reason it does work are by a combination of pure change, and the wierdness that is implicit typecast and transformation in php

     

     


     




  • @tiller said:

    I just found the following code in some code i am bugfixing(Aka rewriting)

    if($endtime == 00) {
      $endtime = 0;
    }

    The code had a comment, saying that it was removing the extra 0 if it was there. ($endTime is a string)

    The funny thing about this code is that it actuelly DOES work, and for all practical purposes does what the original author intended

    (That is transform the string "00" to "0") but the reason it does work are by a combination of pure change, and the wierdness that is implicit typecast and transformation in php


    Change it to

    // transform "00" to "0"
    if($endtime == 0) {
      $endtime = 00;
    }

    so your fellow programmers have some fun, too.



  • I <sarcasm mode="extreme">LOVE</sarcasm> PHP's conversion rules.

    (int)'' // two single quotes -> typecasts to integer zero
    ('' == 0) // empty string == integer zero -> results in TRUE
    ('' == null) // empty string == null -> results in TRUE
    (0 == '0') // integer 0 equals string 0 -- as expected. php is supposed to auto-convert by context rules
    empty('0') && empty(0)  // string 0 and integer 0, both evaluate to TRUE
    (0 == '0') && (0 == '00') -> TRUE

    so you'd expect '' == 0 == '0' == null, but nope. bzzzt your program blows up.

    Of course there's the === (values AND types equal) operator, but then you lose any advantages of type auto-conversion. Sigh... Go figure, someone's weekend project to make their website a bit simpler to maintain (hah) becomes a globe-spanning conspiracy to make people tear out their hair chasing obscure bugs because of syntactical warts in a language.
     


     


     

     



  • For the == operator: 

    In the context of strings, only the empty string is considered null.

    In the context of integers, only zero is considered null.

    The string "0" and integer 0 are considered equal.

     

    So why expect "0" to compare to null just because 0 does? It's like converting the integer 4 to a float and expecting it to be equal to 4.3.



  • @Otterdam said:

    So why expect "0" to compare to null just because 0 does?

    It is normal to expect equality to be transitive. Under the usual definition of equality, |- (a = b /\ b = c) -> a = c



  • @asuffield said:

    @Otterdam said:

    So why expect "0" to compare to null just because 0 does?

    It is normal to expect equality to be transitive. Under the usual definition of equality, |- (a = b /\ b = c) -> a = c

    But probably not normal when there is all this implicit type conversion going on. It's like using babelfish to translate text from english to spanish to german to italian and expecting the same result as if you translated english to italian directly.

     



  • @Otterdam said:

    So why expect "0" to compare to null just because 0 does? It's like converting the integer 4 to a float and expecting it to be equal to 4.3.

    Because it makes it very hard in practice to TRULY determine if a variable's actually null, or just has some variant of a zero in it.

    Consider the case of an online form where a particular field can have a zero entered, and is a required field. How do you properly validate that field in PHP? Let's assume the user did enter a simple 0 and hit 'submit':

    1. isset($_REQUEST['field']) is useless, as it'll return true as long as the field was passed on to the server by the UA in the query (whether it's GET or POST is irrelevant, or if there's anything actually in the form field. If it hits the server, isset() is true).
    2. empty($_REQUEST['field']) is even worse. This will be true, even though a 0 was submitted.
    3. Comparison to the empty string will fail as well, because 0 and '' are equivalent as far as PHP's considered.
    4. Using the === operator can be problematic too, if some other part of the software stack converts one of the values to (say) an integer and the other side of the comparison comes out as a string. '0' == 0, but '0' !== 0 because the types don't match.
    4a. Casting both values to a particular type will also fail, as (int)'' is 0, as is (int)null.

    In the end, you're left with the "nice" hack of having to check the string length of the value, as in

    if (strlen($_REQUEST['field]) == 0)
       echo "Hey, this field wasn't filled out";
    }

    I don't have a problem with automatic type conversion. That's the whole point of scripting languages, to be essentially free of typing worries, but at some point the conversions have to be logical. PHP, for all its power, ain't anywhere close to logical.



  • @Quinnum said:

    @asuffield said:
    @Otterdam said:

    So why expect "0" to compare to null just because 0 does?

    It is normal to expect equality to be transitive. Under the usual definition of equality, |- (a = b /\ b = c) -> a = c

    But probably not normal when there is all this implicit type conversion going on. It's like using babelfish to translate text from english to spanish to german to italian and expecting the same result as if you translated english to italian directly.

     


    Good explanation :)



  • This is why the only thing I've written in PHP has an is_really_set() function.



  • @MarcB said:

    Because it makes it very hard in practice to TRULY determine if a variable's actually null, or just has some variant of a zero in it.

    is_null( $_REQUEST['field'] );



  • @asuffield said:

    @Otterdam said:

    So why expect "0" to compare to null just because 0 does?

    It is normal to expect equality to be transitive. Under the usual definition of equality, |- (a = b /\ b = c) -> a = c

    Obviously the = sign doesn't mean equality in PHP, but rather some kind of similarity or so. 



  • == is the equivalence operator in PHP.  === is the equality (actually identity) operator.



  • @ammoQ said:

    @asuffield said:
    @Otterdam said:

    So why expect "0" to compare to null just because 0 does?

    It is normal to expect equality to be transitive. Under the usual definition of equality, |- (a = b /\ b = c) -> a = c

    Obviously the = sign doesn't mean equality in PHP, but rather some kind of similarity or so. 

    Indeed. Which is surprising and kinda silly. 



  • It is for these reasons that PHP is notoriously difficult to validate, secure, and generally work with on any enterprise-level.  Type conversion issues are the number one problem faced by PHP developers these days, and tonnes of unrecyclable, yet still boilerplate, code has to be generated in order to validate not only your input, but the actual type your input is in.



  • @Sunstorm said:

    @MarcB said:

    Because it makes it very hard in practice to TRULY determine if a variable's actually null, or just has some variant of a zero in it.

    is_null( $_REQUEST['field'] );

    Ok, typo on my part. I didn't mean null, more like "actually empty".
     



  • @Soviut said:

    It is for these reasons that PHP is notoriously difficult to validate, secure, and generally work with on any enterprise-level.  Type conversion issues are the number one problem faced by PHP developers these days, and tonnes of unrecyclable, yet still boilerplate, code has to be generated in order to validate not only your input, but the actual type your input is in.

    Well, mostly PHP's just fine for that. It's only when you're dealing with 'zero' inputs that you hit all these problems, because of the PHP creators/maintainers decision to make integer zero, string zero, empty string, and null all equal in the type conversion rules.

    Don't forget that Yahoo's using PHP quite a bit, that's pretty "enterprise". The language has a lot of warts and definitely reflects its "just a couple quick shell scripts to automate some stuff" history, but show me a language that has no warts and I'll show you a language that never ever left its CompSci prof's creator's office. 



  • @Soviut said:

    It is for these reasons that PHP is notoriously difficult to validate, secure, and generally work with on any enterprise-level.  Type conversion issues are the number one problem faced by PHP developers these days, and tonnes of unrecyclable, yet still boilerplate, code has to be generated in order to validate not only your input, but the actual type your input is in.

    Bingo! WTF found, now we can go back to work. Hopefully without PHP... ;) 



  • PHP's type juggling is confusing, but it's really not an issue once you get used to it and memorize what casts as what.

    $var === $var; // A variable is === only when EXACTLY the same, both value and type.

    is_null( $var ) == !isset( $var ); // A variable is_null when it was assigned the value NULL, hasn't been defined yet, or has been unset(). 

    empty( $var ) == ( !$var ); // A variable is empty when it's null (as above), or converts to boolean false. Things that cast to false: null, 0 and any string that converts to it, and empty array.

    $var == $var; // A variable is == when both variables, when converted to boolean are equal.

    There's one additional case, which is in the case of array indices, in which case isset() returns false if the array key was set to null. If you must check for that, there's array_key_exists();
     



  • @Sunstorm said:

    is_null( $var ) == !isset( $var ); // A variable is_null when it was assigned the value NULL, hasn't been defined yet, or has been unset(). 

     And there is yet another one of PHP's built-in stupidities. is_set, isnull.... Why the _? It would be nice if future revision of PHP went through the core of the language with a machete and cleaned up the libraries to have a CONSISTENT and LOGICAL naming convention. At least (I don't think) there's any standard calls in CamelCaps or studlyCaps and whateverVariantionOfCapitalizationYOUwantTOuSe.
     



  • @MarcB said:

    @Sunstorm said:

    is_null( $var ) == !isset( $var ); // A variable is_null when it was assigned the value NULL, hasn't been defined yet, or has been unset(). 

     And there is yet another one of PHP's built-in stupidities. is_set, isnull.... Why the ? It would be nice if future revision of PHP went through the core of the language with a machete and cleaned up the libraries to have a CONSISTENT and LOGICAL naming convention. At least (I don't think) there's any standard calls in CamelCaps or studlyCaps and whateverVariantionOfCapitalizationYOUwantTOuSe.
     


    V6 is apparently fixing alot of things according to wikipedia:

    * Namespace support will be added.

    * Native Unicode support will be added.

    * The magic_quotes option will be removed.

    * The HTTP
    VARS global variables will be removed.

    * The register_globals option will be removed.

    * The safe_mode option will be removed.

    * Late static binding will be added.

    Unfortunately I doubt they will enforce a naming convention or argument order convention, wtf@array
    having the array as the last argument everyone else generally has whatever one is supposed to be working on as the first argument. Renaming functions will break alot of code (unless the deprecate thousands of functions).



  • They could just use the ugly name as an alias to the updated function.  They already include a bunch of aliases.



  • There's so many functions that'd need cleaning up, yeah, it would break the language. But hey, a new x.0 version would be a good time to say "Yeah, previous versions were crap. Try this one, it's less crappy!" and break some backwards compatibility. There's a lot of legacy cruft they could rid themselves of. And new function names would mean new man pages with new comment sections with hopefully fewer examples of horribly bad coding.


    More examples of stupid naming is the array handling area. Looking at the docs, it would seem that all array-specific functions are named array_*(), but not so fast, what about sort? arsort? They all deal with arrays, but there's no array_ prefix. Argh... arsort always gets me. Glance at the name quickly and you'd think "Hmm... ARray SORT", but no. it's Array Reverse Sort. So why array_push/pop/shift/unshift? Pop and its cousins by themselves would fit in with some of the other functions' obvious brevity-in-naming.

    Or usort, uksort? Sorting me and United Kingdom now, are we? If they can have array_uintersect_udiff, usort/uksort should be better renamed to array_sort_callback/array_key_sort_callback.

     

     

    Blah... I'd better get back to work. <30 hours until a hefty project has to be demoed, and many more miles of PHP to scream and kick my way through.

     


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.