Three PHP mistakes that will cause you debugging nightmares

January 21, 2009 – 8:18 pm Tags:

Here are some PHP mistakes I’ve encountered, which have often been very difficult to track down…

Semicolon after while

Recently in some code I was writing, I had a while loop, which looked something like this:

$i = 0;
while($i < 20); {
  //some code here
  $i++;
}

See that semicolon there? This will cause PHP to silently fall into an infinite loop. You will not get any errors even with E_ALL|E_STRICT error levels – beware of this mistake!

empty() and magic __get method

If you have a class with a __get method, beware of using it with empty():

class Example {
  public function __get($name) {
    return 'this should not show up as empty';
  }
}
 
$e = new Example();
if(empty($e->something))
  echo 'This message will show';
 
$var = $e->something;
if(empty($var))
  echo 'This message will not show';

The first if will evaluate to true, even though the following if with exactly the same string will not!

Missing semicolon after break or continue

This one can be tricky to track down:

for($i = 0; $i < 10; $i++) {
  for($j = 0; $j < 10; $j++) {
    if($i == 0)
      break
 
    print $j;
  }
}

The missing semicolon after the break in the inner loop will cause the code to only output “0″ and then exit. This can be tricky to track down, but there is a good way to avoid this completely: always use braces with control structures

In closing

These three are probably the trickiest I’ve actually seen in code, and for #1 and #2 I must admit I was the person who had written the bad code… in my defense, I must say that #1 should be a parse error from PHP (the braces after the while with no “parent”) and #2 does not make any sense! =)

Do you know any more easy to miss errors in code that can be annoying to find?

ps: welcome dzone users

This post has been getting some nice traffic from dzone. I’d like to welcome any new readers – be sure to subscribe to my RSS feed, as you may find my other posts interesting as well. Some examples of my other recently popular posts are what would make template engines actually useful? and the post on how to implement the Data Access Object pattern in PHP

Also, voting for me on dzone is appreciated – just hit the dz button in the Share this list. Thanks!




Be sure to read the comments below for some more mistakes!

Share this:

RSS feed Subscribe to my RSS feed

About the author

Jani is a 15 year veteran of the software industry. He's currently available for consulting

  1. 23 Responses to “Three PHP mistakes that will cause you debugging nightmares”

  2. My #1:

    $arr = array(‘A’, ‘B’, ‘C’);
    foreach ($arr as &$val) {}
    foreach ($arr as $val) {}
    var_dump($arr);

    My #2:
    PHP+UTF+BOM

    By Sam on Jan 21, 2009

  3. I don’t think #1 should be a parse error – it’s just a code block, which is perfectly parseable. And you could’ve just as well used a for loop anyway ;)

    #2 actually does make some sense: the class member itself technically isn’t defined in itself. Instead, calling it returns a value from elsewhere. When that value is then assigned to another variable, that one of course is defined.

    That said, they’re still tricky errors to track down :)

    By Vincent on Jan 22, 2009

  4. #1 depends on how you look at it. If you have { } without a control statement, it doesn’t affect anything in any way (afaik) – it’s useless – so why is it allowed?

    By Jani Hartikainen on Jan 22, 2009

  5. Good post and great blog! I don’t have any examples as good as those, but one thing actually caused some headache recently. I wanted to know whether an url also contains the scheme (http-prefix) and I used strpos-function. Of course the scheme’s position (if exists) in the string starts from index 0 and I used the !-operator instead of strict comparison with === -operator and yes, you can guess the rest… :)

    true
    if (strpos($url, “http”) === false)
    // returns false
    ?>

    This is quite obvious and it’s also written in the documentation, but it’s easy to miss :)

    By Olli on Jan 22, 2009

  6. Damn, the php-code doesn’t appear correctly in the previous post. Let’s try without the php-tags.

    $url = “http://foobar.com/”;

    if (!strpos($url, “http”))
    // returns true, because !0 => true
    if (strpos($url, “http”) === false)
    // returns false

    By Olli on Jan 22, 2009

  7. I say: all embrace python’s way of doing it..

    By Harro on Jan 22, 2009

  8. Well, parse errors refer to incorrect syntax – a code block is perfectly normal syntax. If you say if((true)) then the inner brackets are useless as well – should that not be allowed?

    By Vincent on Jan 22, 2009

  9. To solve your second problem just implement the magic method __isset. (http://www.php.net/__isset) The method __isset() is triggered by calling isset() or empty() on inaccessible members.

    By be.coded on Jan 22, 2009

  10. Exactly what be.coded said. Anytime you implement __get, you should be implementing __isset.

    something)) {
    echo ‘Empty’;
    } else {
    echo ‘Not empty’;
    }
    ?>

    With the code above, you’ll get “Not empty” all the time.

    By David Stockton on Jan 23, 2009

  11. That’s a good point, though it’s not obvious that empty would require isset (unless you’ve learned the manual word for word) which is why I listed it.

    Also, I wonder if there’s a nice way to enable usage of some html tags in comments for pasting code… it’s not nice that WP screws up your comments.

    By Jani Hartikainen on Jan 23, 2009

  12. #1 is absolutely no fault. Looks correct.

    If you think PHP should teach you not to do stupid things then better go to school… and try again or look at C++

    By resmo on Jan 23, 2009

  13. Well, in fact I would add another one very difficult to detect, related with empty:

    empty($v) when $v = “0″;

    $v is a string, and you expect empty($v) return false, but empty(“0″) returns true!!

    I wrote a post about this a week ago, called
    the PHP empty function is wrong, just because of this behavior (which could make sense at some level) but is not what one expects.

    By Pau Sanchez on Jan 23, 2009

  14. You can actually wrap miscellaneous parts of your code with curly braces. I’ve seen this done before to organize the code…Maybe some IDE’s use this for collapsing code blocks, who knows? It is legal though.

    By kevin on Jan 23, 2009

  15. I learned long ago to implement “is equal to” and “is identical to” comparisons with this syntax:

    // is equal too
    if (“foo” == $foo) {…}

    // is identical to
    if (“foo” === $foo) {…}

    This helps avoid inadvertently assigning a variable the value of “foo” since:

    if (“foo” = $foo)

    will raise an error. This tip might be common knowledge but I thought I would mention it.

    By nathan on Jan 26, 2009

  16. @Nathan

    Yes – it’s a classic. Assignment instead of comparison due misuse of the equals sign.

    And cool – your approach with the variable in the letter position will cause an error and’ll not silently change the value if one of the equal signs is missing.

    By polarizer on Jan 27, 2009

  17. Also this one never gets old:

    try to find out why something isnt comparing…

    if($row['something'] != ”){
    //do something
    }

    when the row returns ‘NULL’.

    By Oliver Leitner on Jan 29, 2009

  18. I’ve been a victim of the first mistake for a few times. I also make a lot of mistakes from upper case and lower case letters in the code.

    By Orlando Orthodontist on Oct 27, 2009

  1. 6 Trackback(s)

  2. Jan 22, 2009: Tracking the user’s browsing history with PHP | CodeUtopia
  3. Feb 3, 2009: Are You Making These 10 PHP Mistakes? - NETTUTS
  4. Feb 4, 2009: Even more PHP mistakes! | CodeUtopia
  5. Jun 4, 2009: Recommened PHP articles to improve your programming skills! | JortK.nl
  6. Dec 19, 2010: [Linkdump #22] PHP… po raz trzeci! « Tomasz Kowalczyk
  7. Jan 19, 2011: 10 most common PHP Mistakes! « Itupdates4u’s Weblog

Post a Comment

You can use some HTML (a, em, strong, etc.). If you want to post code, use <pre lang="PHP">code here</pre> (you can replace PHP with the language you are posting)