Scope battles

25 11 2006

PHP allows you to define functions inside other functions. Example:

class C {
  function m() {
    function do_magic($x) { return $x + 42; }
    $var_magic = 42;
  }
}

Actually it’s a function inside a method, but it doesn’t matter here. Class C has been added to the global scope, so we can refer to its name and create instances. And do_magic of course is not visible outside of the class definition, right?

echo do_magic(5); // => "Call to undefined function: do_magic()"

Right. OK, let’s make an actual object and call a method.

$c = new C;
$c->m();

All fine. Is $var_magic visible outside of a method?

echo $var_magic; // => null

Of course not. What about a do_magic function?

echo do_magic(5); // => 47

That’s pretty bad, isn’t it? Variables have its local scope inside functions, but functions have only one scope: global. Except when they are methods. But hey, it’s a feature, not a bug, so don’t feel too bad about it.

It hit me today, when I defined a function inside a method and (silly me!) wanted to use a method second time:

$c->m(); // => "Cannot redeclare do_magic()"

I’ve spent few moments to understand what redefining function foo() from file bar.php on line 1 originally defined in the same place meant.

Fatal error: Cannot redeclare do_magic() (previously declared in /var/www/foo.php:42) in /var/www/foo.php on line 42

But I finally got that one. Solutions? Define all your functions outside of other definitions. Or use function_exists.

No rant today, sorry. Go study the Zen of PHP instead.





PHP useless indexes

17 11 2006

There’s something terribly wrong in the way PHP parses its input. Look at this simple piece of code:

array(1,2,3)[0]

In any decent language you’d expect this expression to return 1. But not in PHP:

Parse error: syntax error, unexpected ‘[‘

Only solution seems to be to use some temporary variable or function to get a value from newly created array in the same expression.

function get($a, $n) { return $a[$n]; }
echo get(array(1, 2, 3), 0); // => 1

It hurts most when you work with functions that return arrays of values. You can’t write:
localtime()[2] to get current hour, you can’t write:
stat('some_path')[7] to get size of file or:
split(':', 'root:x:0:0:root:/root:/bin/bash')[6] to get shell used by root.

And to get things worse, string indexes behave the same way…