
3 things you might not know about PHP
It's not a secret for any of the web developers that PHP is a simple, flexible and not demanding language. But when working with this language, you can come across unexpected things. In this article, I will present “strange facts” and explain why PHP gives such results.
Most of you probably know that floating point numbers cannot really represent all real numbers. In addition, some operations between two seemingly well-defined numbers can lead to unexpected situations. This is because the accuracy with which a computer stores numbers has its own characteristics. This phenomenon affects not only PHP, but also all programming languages. Inaccuracy in floating point operations has caused considerable headache to programmers since the founding of the discipline as such.
This fact has already been written more than once. One of the most important articles is “What Every Computer Specialist Should Know About Floating-Point Operations”. If you have never read it, I highly recommend that you fix this.
Let's look at this small piece of code:
What do you think will be the result? If you assume that the result of the operation is 8, then you are mistaken. Actually 7. Those who have the Zend certificate, this example is already known. By the way, you can find this example in the Zend Certification Preparation Guide.
Now let's see why this happens:
The result of this operation is stored in reality as 0.79999999999, and not 0.8, as you might think. This is where the problems begin.
The second operation that we perform:
This operation works as it should, but the problems remain.
Finally, the third and final operation:
This expression uses explicit type conversion. When the value is cast to int, PHP truncates the fractional part and ultimately returns 7.
During operation, we always use increment / decrement operations similar to data: Each of us easily understands what is happening here. But try to figure out what this code will output: Let's see: Not so complicated, right? Now let's increase the complexity a bit. Have you ever tried to increment strings before? Try to assume that this code will output: This task is already more difficult. Let's see what we got:
Surprised? By incrementing a line that ends with a digit, we will actually increase the character (by the next character in the alphabetical order, i.e. after t follows u). Regardless of whether the line starts with a digit or not, the last character will be changed. However, this operation does not make sense if the string ends with a non-alphanumeric character.
This point is well described in the official documentation on increment / decrement operations, but many did not read this material because they did not expect to see anything special there. I want to admit that until recently I thought exactly the same.
You are an array master in PHP. Do not be shy about it. You already know everything about creating, editing, and deleting arrays. However, the following example may surprise you.
Very often when working with arrays you have to look for something in them. PHP has a special function for this in_array (). Let's see it in action: What should be deduced? Isn't that a little strange. We have an associative array that contains only Boolean values, and when we search for a string, we get true. Is this really magic? Let's see another example: And what do we get? And again in_array () returned true. How is this possible?
You have just used one of your favorite and hated PHP functions at the same time. I must say that PHP is not a strictly typed language. Many problems are precisely because of this. In fact, all of the following values, if compared by PHP, are identical when using the single comparison operator: By default, in_array () uses a "flexible" comparison, so non-empty ("") and non-zero string ("0") are equivalent to true, this the same applies to all nonzero elements (e.g. 1). Therefore, in our first example, we got true because 'phpmaster.com' == true, while in the second example 'aurelio' == 1. To solve this problem, you must use the third additional parameter in the in_array () function which allows strict comparison of elements. If we now write:
we will get false.
In this article, you saw the strange and unexpected behavior of a PHP interpreter. Here is what you could learn from what you read:
If you are an advanced programmer, then most likely you already knew about the existence of these oddities, but repetition is never worthless.
Floating point inaccuracies
Most of you probably know that floating point numbers cannot really represent all real numbers. In addition, some operations between two seemingly well-defined numbers can lead to unexpected situations. This is because the accuracy with which a computer stores numbers has its own characteristics. This phenomenon affects not only PHP, but also all programming languages. Inaccuracy in floating point operations has caused considerable headache to programmers since the founding of the discipline as such.
This fact has already been written more than once. One of the most important articles is “What Every Computer Specialist Should Know About Floating-Point Operations”. If you have never read it, I highly recommend that you fix this.
Let's look at this small piece of code:
echo (int) ((0.1 + 0.7) * 10);
What do you think will be the result? If you assume that the result of the operation is 8, then you are mistaken. Actually 7. Those who have the Zend certificate, this example is already known. By the way, you can find this example in the Zend Certification Preparation Guide.
Now let's see why this happens:
0.1 + 0.7 = 0.79999999999
The result of this operation is stored in reality as 0.79999999999, and not 0.8, as you might think. This is where the problems begin.
The second operation that we perform:
0.79999999 * 10 = 7.999999999
This operation works as it should, but the problems remain.
Finally, the third and final operation:
(int) 7.9999999 = 7
This expression uses explicit type conversion. When the value is cast to int, PHP truncates the fractional part and ultimately returns 7.
- If you cast this expression to a float, rather than int, or don’t do type casts at all, you will get the number 8, as you expected
- It is precisely because there is a mathematical paradox that 0.999 ... equals 1, and we got this error.
How PHP "increments" strings
During operation, we always use increment / decrement operations similar to data: Each of us easily understands what is happening here. But try to figure out what this code will output: Let's see: Not so complicated, right? Now let's increase the complexity a bit. Have you ever tried to increment strings before? Try to assume that this code will output: This task is already more difficult. Let's see what we got:
$a = 5;
$b = 6;
$a++;
++$b;
$a = 1;
$b = 3;
echo $a++ + $b;
echo $a + ++$b;
echo ++$a + $b++;
4
6
7
$a = 'fact_2';
echo ++$a;
$a = '2nd_fact';
echo ++$a;
$a = 'a_fact';
echo ++$a;
$a = 'a_fact?';
echo ++$a;
fact_3
2nd_facu
a_facu
a_fact?
Surprised? By incrementing a line that ends with a digit, we will actually increase the character (by the next character in the alphabetical order, i.e. after t follows u). Regardless of whether the line starts with a digit or not, the last character will be changed. However, this operation does not make sense if the string ends with a non-alphanumeric character.
This point is well described in the official documentation on increment / decrement operations, but many did not read this material because they did not expect to see anything special there. I want to admit that until recently I thought exactly the same.
Secret of meanings
You are an array master in PHP. Do not be shy about it. You already know everything about creating, editing, and deleting arrays. However, the following example may surprise you.
Very often when working with arrays you have to look for something in them. PHP has a special function for this in_array (). Let's see it in action: What should be deduced? Isn't that a little strange. We have an associative array that contains only Boolean values, and when we search for a string, we get true. Is this really magic? Let's see another example: And what do we get? And again in_array () returned true. How is this possible?
$array = array(
'isReady' => false,
'isPHP' => true,
'isStrange' => true
);
var_dump(in_array('phptime.ru', $array));
true
$array = array(
'count' => 1,
'references' => 0,
'ghosts' => 1
);
var_dump(in_array('aurelio', $array));
true
You have just used one of your favorite and hated PHP functions at the same time. I must say that PHP is not a strictly typed language. Many problems are precisely because of this. In fact, all of the following values, if compared by PHP, are identical when using the single comparison operator: By default, in_array () uses a "flexible" comparison, so non-empty ("") and non-zero string ("0") are equivalent to true, this the same applies to all nonzero elements (e.g. 1). Therefore, in our first example, we got true because 'phpmaster.com' == true, while in the second example 'aurelio' == 1. To solve this problem, you must use the third additional parameter in the in_array () function which allows strict comparison of elements. If we now write:
0
false
""
"0"
null
array()
$array = array(
'count' => 1,
'references' => 0,
'ghosts' => 1
);
var_dump(in_array('aurelio', $array, true));
we will get false.
Conclusion
In this article, you saw the strange and unexpected behavior of a PHP interpreter. Here is what you could learn from what you read:
- never trust floating point numbers;
- double check the data type before using it;
- Be aware of the problems of “flexible” comparisons and “flexible” types.
If you are an advanced programmer, then most likely you already knew about the existence of these oddities, but repetition is never worthless.