String Comparison Gotchas in PHP

Discussion in 'PHP' started by pradeep, Jul 21, 2007.

  1. pradeep

    pradeep Team Leader

    Joined:
    Apr 4, 2005
    Messages:
    1,645
    Likes Received:
    87
    Trophy Points:
    0
    Occupation:
    Programmer
    Location:
    Kolkata, India
    Home Page:
    http://blog.pradeep.net.in
    Recently, an obscure detail in the way PHP processes strings came to my attention.

    This is processed by code that checks for simple lists (like 1. blah 2. blah, or - blah - blah, etc.). However, an innocent call to in_array($x, array('1.', '0.')) had surprising and unexpected results: our friendly PHP determined that '01' was in the array('1.', '0.')!! This is of course patently false, and made little to no sense until I realized that unlike my previous understanding (when comparing an integer to a string, the string is converted to an integer), PHP actually converts all numeric-like strings into integers when comparing them, so that this code emits bool(true):
    PHP:
    <?php
    var_dump
    ('01' == '1.');
    ?>
    This, of course, seems completely counter-intuitive to me, as I would instead use this code if I wished to check a string for numericness:
    PHP:
    <?php
    var_dump
    ('01' == 1);
    ?>
    and continue on my way. What this actually means is that PHP is imposing a new set of rules upon those of us who wish to simply compare our strings in peace. Note that in ANY situation that you have input from uncontrolled sources, and wish to check for comparison to a numeric string, you MUST do one of the following:

    1. use === instead of ==. This will enforce type checking, so that strings are compared as strings
    2. use the 3rd parameter of in_array(), and set it to true
    3. use strcmp() or one of its cousins
    If you follow these three rules every time that you compare two strings that should not be compared as numbers, you will be OK.

    Note that if you ignore these rules, it could lead to serious security implications, as ==/in_array() will unexpectedly return true in cases where it should not.

    Also note that switch/case suffer from the same deficiency, and if there is any chance you will need something like "case '1' :" then you should be using a different system like "if ($a === '1') then blah elseif()..."

    In my humble opinion, this auto-conversion is dangerous, but as with many useful features that are so flexible, there is a large precedent for people thinking it is useful enough to outway the danger. I personally think PHP could retain all the benefits of loose typing while removing the auto-conversion of numeric strings to ints just when comparing two strings with == and we would all live happily ever after, but who am I to talk - I just use the language.

    The important thing is that anyone out there using == and in_array() improperly or with the wrong understanding needs to fix their code right away to avoid weird and hard to debug edge case behavior.
     
  2. LenoxFinlay

    LenoxFinlay Banned

    Joined:
    Apr 15, 2009
    Messages:
    46
    Likes Received:
    0
    Trophy Points:
    0
    __toString() or not to String

    PHP version 5 introduced a handy new magic method, __toString(), which lets you do something to the tune of:
    class Person {
    private $name;

    function __construct($name="John Doe"){
    $this->name = $name;
    }

    function __toString(){
    return (string) $this->name;
    }
    }

    $bob = new Person('Bob');

    echo $bob; //prints Bob That's nice and convenient. But what if I want to add a little punch:
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice