I like PHP, it is an easy, flexible language. We type something, refresh our browser and see results. No compilation, everything works “out of the box”. But we should be very carefull with PHP, with it’s flexibility out of the box it comes with some strange behaviours. Probably you will never find them in your code base, but forewarned is forearmed.

I’m not going to tell you about trick with floating numbers, I think it is commonly known between PHP developers. Just try to guess the output of this sample code:

<?php

echo (int) ((0.1 + 0.7) * 10);

References

When we unset the reference, we only break the binding between variable’s name and variable’s content. This does not mean that variable’s content will be destroyed.

<?php

$foo = 'bar';
$baz = &$foo;
unset($foo);

echo $baz; // 'bar'

In the example above variable $baz still contains reference to bar content. PHP will remove this content only after all references will be destroyed.

Unset

Let’s continue our research in unset operator. PHP manual says: “unset() destroys the specified variables”. Very clear, yes? But it becomes very tricky, when it is used inside a user function.

Globalized variable

If we unset a globalized variable inside a function, only the local variable is destroyed. The variable in the calling environment will retain the same value as before unset() was called.

<?php

function destroy_val() 
{
    global $val;
    unset($val);
}

$val = 'test';
destroy_val($val);
echo $val(); // test

If we want to unset a global variable we should use $GLOBALS array:

<?php

function destroy_val() 
{
    unset($GLOBALS['val']);
}

Variable passed by reference.

Here is some code sample:

<?php 

function foo(&$bar) 
{
    unset($bar);
    $bar = 'baz';
}

$bar = 'test';
echo $bar, "\n"; // test

foo($bar);
echo $bar, "\n"; // ?

What do you think about the value of $bar variable? We know that when we pass arguments by reference into a function, these variables may change their values in the parent scope. But what about unset() call?

It turnes out that PHP will destroy only a local variable, a parent scope will not be touched. The variable in the calling environment will be the same as before unset() call. The output of the above code sample will be:

test
test

Static variables

What do we know about static variables? They save their values between function calls. But what if we unset a static variable?

<?php

function foo()
{
    static $bar = 1;
    $bar ++;

    echo "Before:", $bar, ", ";
    unset($bar);

    $bar = 'test';
    echo "after:", $bar, "\n";
}

foo();
foo();
foo();

Here PHP will destroy a variable only in the context of the rest of a function.

Before unset: 1, after: test
Before unset: 2, after: test
Before unset: 3, after: test

Switch

Switch operator is the basics. When we learned PHP we also learned switch opeator and it’s behaviour.

<?php

$a = 'foo';

switch($a) {
    default: echo 'default'; break;
    case 'foo': echo 'foo'; break;
    case 'bar': echo 'bar'; break;
    case 'baz': echo 'baz'; break;
}

What is the output? From the manual we know about default section that … this case matches anything that wasn’t matched by the other cases. It is also written that It is important to understand how the switch statement is executed in order to avoid mistakes. The switch statement executes line by line (actually, statement by statement). But it turnes out that not always in order line by line. Default block will be executed the last, even it is on the first line. So the output will be foo.

Strings increment/decrement

Eveything is clear when we use increment/decrement with numbers. Just add or sub 1 from the number. And what if we use strings?

<?php

$string = 'string';
echo ++$string, "\n"; 

$string = 'aa';
echo $string, "\n";

$string = 'zz';
echo $string, "\n";

$string = '12';
echo $string, "\n";

$string = 'string';
echo --$string, "\n";

$string = '12';
echo --$string, "\n";

The output of this code is very interesting.

strinh
ab
aaa
13
string
11

When we have a number which is represented as a string, the logic is clear. Something strange happens with other strings. And it is impossible to guess the result without reading manual. PHP follows Perl’s rules when dealing with arithmetic operations on character variables. Another words you should consider characters as their ASCII codes. And one notice here, that they cannot be decremented.

Ternary Operator

Imagine that you work with a legacy code and you have found something like this:

<?php

echo (true?'true':false?'t':'f');

A stack of ternary expressions. What result do you expect to see? True? If so, you are wrong. When you stack ternary expressions they are evaluated from left to right. Let’s be more verbous in the previous example.

<?php

echo ((true ? 'true' : false) ? 't' : 'f');

Parentheses help now to unserstand how stack of ternary expressions works. Now it’s clear that the output will be t.

Conclusion

Ofcourse you can say that you will never write such code, and you are right. Here we have a set of bad practices. But no one is safe from the legacy code and you should be prepared to understand how PHP behaves in such situations.