PHP functions as lazy variables
Along with finally giving us anonymous functions, PHP 5.3 also gave us namespaces. This has been a looong time coming for PHP. Finally we can develop without polluting the global namespace! Or can we?
As it turns out, PHP namespaces only apply to classes, constants, and functions. Which means this:
namespace foo;
$bar = 1;
… sets $GLOBALS['bar']
to 1
across all namespaces, instead of just
locally to foo
. Sigh.
I’ve been playing with different idioms to get around this. First I tried static class variables:
namespace foo;
class data {
static $bar = 1;
}
// in another namespace
echo foo\data::$bar;
That’s pretty fugly. I don’t like having to lowercase a class name, but it would
be even uglier as foo\Data::$bar
. The biggest problem with this is that I also
want to do this:
namespace foo;
class data {
static $bar = new Bar();
}
But property initializers suck in PHP, and don’t allow complex expressions. I don’t want to start adding initializer logic to the class or at the module level, so that method is out.
I ended up going with:
namespace foo;
function bar($newBar=null) {
static $bar;
if (!isset($bar) || isset($newBar))
$bar = $newBar ?: new Bar();
return $bar;
}
// in another namespace
echo foo\bar()->baz;
It also allows you to pass in a new value manually, if needed. This comes in useful for unit testing:
foo\bar(new MockBar());
I think that’s about as simple as you can get it. Bonus points: your namespace
properties are now lazy loaded. new Bar()
isn’t executed until the first time
you call the function. If you never call it, no overhead.