3 Strange PHP Facts You May Not Know

There is no doubt: PHP is an easy, flexible, and forgiving language. But it can also exhibit some surprising behavior. In this article I’ll present some “strange facts” and explain why PHP gives the results it does.

Floating Point Imprecision

Most of you probably know that floating-point numbers cannot really represent all real numbers. Besides, some operations between two well represented numbers can lead to surprising situations. This is because the finite precision with which computers represent numbers and so it affects not just PHP but all the programming languages. Inaccuracies in floating point problems have been given programmers headaches from the beginning of the discipline.

About this question many words have been said, but one of the most important articles written is What Every Computer Scientist Should Know About Floating-Point Arithmetic. If you’ve never had a chance to read it, I strongly suggest you do so.

Let’s look at this very small snippet:

<?php
echo (int) ((0.1 + 0.7) * 10);

What do you think will be the result? If you guessed 8, you’d be wrong… I’m sorry, you lost the prize! This code will actually print 7! For those who have a Zend Certification, this example is already known. Infact, you can find it in Zend PHP 5 Certification Study Guide.

Now let’s see why this happens. The first operation executed is:

0.1 + 0.7 // result is 0.79999999999

The result of the arithmetic expression is stored internally as 0.7999999, not 0.8 due to the precision issue, and this is where the problem starts.

The second operation executed is:

0.79999999 * 10 = 7.999999999

This operation works well but preserves the error.

The third and last operation executed is:

(int) 7.9999999 // result is 7

The expression makes use of an explicit cast. When a value is convert to int, PHP truncates the decimal portion of the number which makes the result 7.

There are two interesting things to note here:

  • If you cast the number to float instead of int, or if you don’t cast at all, you’ll get 8 as result as you expected.
  • Although the CPU doesn’t know, and we actually we got this error due to its imprecisions, it’s working accordingly to the mathematics paradox that asserts 0.999… is equal to 1.

To conclude this point, I’d like to cite the Zend PHP 5 Certification Study Guide Second Edition:

Whenever the precision of your calculation is a relevant factor to the proper functioning of your application, you should consider using a (sic) the arbitrary precision functions provided by the BCMath extension (you can search for it in your copy of the PHP manual) instead of PHP’s built-in data types.

How PHP “Increments” Strings

During our everyday work we write instructions that perform incrementing/decrementing operations like these:

<?php
$a = 5;
$b = 6;
$a++;
++$b;

Everyone easily understands what’s going on with those statements. But given the following statements, guess what will be the output:

<?php
$a = 1;
$b = 3;
echo $a++ + $b;
echo $a + ++$b;
echo ++$a + $b++;

Did you write down your answers? Good. Let’s check ‘em all.

4
6
7

Not too difficult, right? Now let’s raise the bar a little. Have you ever tried to increment strings? Try to guess what the output will be for the following:

<?php
$a = 'fact_2';
echo ++$a;

$a = '2nd_fact';
echo ++$a;

$a = 'a_fact';
echo ++$a;

$a = 'a_fact?';
echo ++$a;

It’s not so easy this time, is it. Let’s uncover the answers.

fact_3
2nd_facu
a_facu
a_fact?

Surprised? Using an increment operator on a string that ends with a number has the effect of increasing the letter (the one following it in the alphabet, e.g. t -> u). Regardless if the string starts with digits or not, the last character is changed. But there is no effect if the string ends with a non-alphanumeric character.

This is well documented by the official documentation about the incrementing/decrementing operators but most of you may not have read it because you probably thought nothing special was there. I must admit I thought the same until a short time ago.

PHP follows Perl’s convention when dealing with arithmetic operations on character variables and not C’s. For example, in PHP and Perl $a = ‘Z’; $a++; turns $a into ‘AA’, while in C a = ‘Z’; a++; turns a into ‘[‘ (ASCII value of ‘Z’ is 90, ASCII value of ‘[‘ is 91). Note that character variables can be incremented but not decremented and even so only plain ASCII characters (a-z and A-Z) are supported. Incrementing/decrementing other character variables has no effect, the original string is unchanged.

The Mystery of Value Appearance

You’re a real array master in PHP, admit it. Don’t be shy. You already know everything about how to create, manage, and delete arrays. Nonetheless, the next example might surprise you at first sight.

Often you work with arrays and need to search if a given value is in an array. PHP has a function for this, in_array(). Let’s see it in action:

<?php
$array = array(
  'isReady' => false,
  'isPHP' => true,
  'isStrange' => true
);
var_dump(in_array('sitepoint.com', $array));

What will be the output? Place your bets and let’s check it.

true

Isn’t this a little bit strange? We have an associative array where its values are all boolean and if we search for a string, we got true. Has this value magically appeared? Let’s see another example.

<?php
$array = array(
  'count' => 1,
  'references' => 0,
  'ghosts' => 1
);
var_dump(in_array('aurelio', $array));

And what we get is…

true

Once again the in_array() function returns true. How is this possible?

You’re experiencing one of both best and worst, loved and hated PHP features. PHP isn’t strongly typed and this is where the error starts. In fact, all the following values, if compared in PHP, are considered the same unless you use the identity operator:

  • 0
  • false
  • “”
  • “0″
  • NULL
  • array()

By default, the in_array() function uses the loose comparison, a non-empty ("") and non-zero-filled ("0") string is equal to true and to all non-zero numbers (like 1). Hence, in the first example we got true because 'sitepoint.com' == true, while in the second we have 'aurelio' == 0.

To solve the problem you’ve to use the third and optional parameter of in_array() that allows you to compare the values strictly. So, if we write:

<?php
$array = array(
  'count' => 1,
  'references' => 0,
  'ghosts' => 1
);
var_dump(in_array('aurelio', $array, true));

we’ll finally get false as we expect!

Conclusions

Throughout this article you’ve seen some strange and unexpected behaviors you might experience while using PHP. The lessons to take away from these examples are:

  • Never trust floating point numbers
  • Double check what data type you’ve before using them in operations
  • Be aware of the problems of loose comparisons and loose data types

If you’re an advanced user, you probably already knew them already, but a refresher is never worthless.

Image via Fotolia

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.imblog.co.za/ Ian

    Really interesting post, busy self learning MySQL and PHP and this was a good read. I do have one question, what does the ++$b do in the echo statement (echo $a + ++$b;) do?

    $a + ++$b;

    • http://www.audero.it/ Aurelio De Rosa

      Hi Ian and thank you for the comment. About the statement, at the time it’s executed, $a is 2 and $b is 3 from the previous line.
      Since the statement has ++$b, before do the sum, $b is incremented so the final operation is:
      echo 2 + 4; // echo 6

    • Thiago

      ++$b will use the actual value then after use it increment

  • Jasontxf

    If i’m not wrong, by putting the ++ at the front of the variable, the variable perform the operation before using the value and if place at the back, the variable will be used before performing the operation.
    In this case, ++$b will increase $b by one before using the value.
    Example:
    $b = 1;
    echo ++$b; // returns 2
    $b = 1;
    echo $b++; //returns 1
    echo $b; // returns 2

  • Tanmay

    Nice Refresher! i had literally forgot the true option of in_array function! thanks for reminding me :)

  • http://okeowoaderemi.com okeowo aderemi

    Whoa, so many PHP glitches i never knew about, this is a very interesting post especially for applications centered around Core Calculations. i never use the in_array i always prefer to check it myself. Nice Post

    • http://www.audero.it/ Aurelio De Rosa

      Glad to know you liked the article. Keep reading us ;)

  • Thomas

    Sounds like ghosts in the machine.

  • Horace B Middlevale

    I was interested to try php but I keep seeing articles like this one talking about bizarre language details that result in unexpected and unguessable behaviors and decided to stay with languages that are at least slightly sane.

    • http://www.audero.it/ Aurelio De Rosa

      Don’t be scared by behaviors like these. PHP is a great language when it comes to quickly writing a web application.

  • http://techishard.wordpress.com/ Grant Wesley Parks

    I must be missing something about the last issue. I feel the main point to make here is the wrong array function is being used for a hash/dictionary type array — we should be using array_key_exists(). And the core reason behind the confusion you illustrate is that in_array is searching array *values*, when it’s apparent we should be looking at the keys.

    • http://www.audero.it/ Aurelio De Rosa

      No, the function in_array() is exactly what we want. The strange behaviour is that if you’ve an array of boolean and you search for a string (as a value), the in_array() function gives you true, as if the string was a boolean, unless you use true as third parameter. This happen because PHP is a loosy typed language.

      • http://techishard.wordpress.com/ Grant Wesley Parks

        I know why it’s doing what it is doing. But it is obvious from the problem that we don’t want to search values.

  • http://www.maltblue.com Matthew Setter

    Aurelio,
    Just a quick one to say thanks for the refresher. I knew most of them, but the point on arrays was definitely one’d that I’d forgotten. As you said, a refresher is always handy.
    Matt

  • http://techankit.com ankit

    wow …interesting tricks …thanks for sharing …but i didn’t understood why you have used var_dump function??

    • http://www.audero.it/ Aurelio De Rosa

      I used var_dump for clarity. If you echo a boolean, it’ll print 1 if the value was true and “nothing” (actually an empty string) in case of a false value.

  • http://www.linkedin.com/in/hidran Hidran Arias

    This one could also be a surprise and a cause of lot of bugs: $string=’my string’;
    echo count($string);
    //it outputs 1!

  • http://cybermogi.com Ari Mogi

    just realized the fact and wonder. I think we need a php-built-in-function to check variables stored like fact #1. #PHPFacts

  • http://guisheng.li g.lee

    thank you for the post, i didn’t know these strange facts before

    • http://www.audero.it/ Aurelio De Rosa

      Don’t worry if you didn’t know them, isn’t so common to run into this issues and the second in particular is quite surprising.

  • Dima

    I was intresting and hm…simply writen. Thank you for your work)

  • http://www.tech-licious.com Umair Abid

    Hey Aurelio, Suppose I have a multi-dimensional array like,
    $array = array(
    ’1′ => array(),
    ’2′ => array(),
    ’3′ => null
    )

    Than will the in array function will return true, in every case whether I search for an empty or non empty value. Thanks,

    • http://www.audero.it/ Aurelio De Rosa

      Hi Umair. Since you’re array is currently filled with “empty” values, you’ll get true only if you search for other “empty” values like an empty string or zero. For example, in your array:
      $array = array(
      ’1′ => array(),
      ’2′ => array(),
      ’3′ => null
      );
      if you test the following:
      var_dump(in_array(”, $array));
      var_dump(in_array(array(), $array));
      var_dump(in_array(‘aurelio’, $array));
      you’ll get:
      true
      true
      false
      because the empty string match the null, the empty array match the first empty array and the string 'aurelio' match nothing because it’s a non-empty value. To have a complete overview on this, please referrer to the PHP documentation

  • LayZee

    I still don’t get why ‘aurelio’ equals 0. Can you help me out? :-) I would expect a non-empty string to equal 1, true, etc.