< / >

This is a blog by about coding and web development.

PHP functions as lazy variables

Posted on in

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.

Pecs / BDD for PHP

Posted on in

pecs is a teensy behavior-driven development library for PHP 5.3, a la RSpec or JSpec. I’ve been working on it for the last week and I think it’s off to a good start. It gives you tests that look something like:

describe("Bowling", function() {
    it("should score 0 for a gutter game", function() {
        $bowling = new Bowling();
        for ($i=0; $i < 20; $i++) {
            $bowling->hit(0);
        }
        expect($bowling->score)->to_equal(0);
    });
});

You can read more on GitHub.

Anonymous functions in PHP 5.3

Posted on in

The PHP wiki has a great developer walkthrough of the hows and whys of the new lambda in PHP 5.3. I’ve been digging around for something like this for a while. There are some important distinctions about the way PHP lambdas work, especially if you’re used to closures in languages like JavaScript.

Highlights:

  • Lambdas do not automatically inherit surrounding scope. You must specify the variables you want to be available to the method:
$foo = 1;
      $bar = function() use($foo) {
          echo "$foo\n";
      };
  • Lambdas cannot be invoked directly when assigned to an object property:
$foo = new stdClass();
      $foo->bar = function() {
          echo "hello, world!\n";
      };
      $foo->bar(); // will trigger an error

      // assign it to a temporary variable instead
      $bar = $foo->bar;
      $bar();
  • Lambdas will throw an error when serialized
  • Lambdas have no $this scope

PHP micro-frameworks

Posted on in

There have been quite a few Sinatra-inspired micro-frameworks popping up for PHP recently. I’m loving this trend. PHP actually almost feels like a real life modern language with 5.3, and micro-frameworks are doing a good job trying to make it pretty.

The first one I saw was Fitzgerald, which looks like this:

include('lib/fitzgerald.php');

class Application extends Fitzgerald {
    function get_hello() {
        return "Hello, world!";
    }

    function get_hello_name($name) {
        return "Hello, {$name}!"
    }
}

$app = new Application();
$app->get('/hello', 'get_hello');
$app->get('/hello/:name', 'get_hello_name');
$app->run();

Fitzgerald was first to the scene but is still my favorite overall – it sucks to have to define a class for your site, but the framework is tiny, easy to use, and keeps to itself.

Limonade showed up next:

require_once 'lib/limonade.php';

dispatch('/hello', 'hello');
function hello() {
    return 'Hello world!';
}

dispatch('/hello/:name', 'hello_name');
function hello_name() {
    $name = params('name');
    return "Hello, {$name}!";
}

run();

Limonade was a nice effort at ridding us of the class definition, but it craps all over the global namespace, and doesn’t support PHP 5.3 lambdas.

And finally came Fat-Free PHP:

require_once 'lib/F3.php';

F3::route('GET /hello', function() {
    echo 'Hello, world!';
});

F3::route('GET /hello/@name', function() {
    $name = F3::get('PARAMS[name]');
    echo "Hello, {$name}!";
});

F3::run();

F3 really feels like Limonade on steroids. I love that they allow lambdas. I hate their parameter syntax though, and I think they try to do too much: F3 also includes a template engine and a database helper, which is a bit overboard for me. They do it all in one file, though, which is commendable.

If someone really embraced PHP 5.3 you could do something much closer to the gold standard Sinatra, without global namespace pollution. If you had an http namespace that accepted lambdas, it could be very sexy:

require 'lib/http.php';

http\get('/hello', function() {
   echo "Hello, world!"
});

http\get('/hello/:name', function($name) {
    echo "Hello, {$name}!";
});

http\run();

Or, if you just worked within the http namespace:

namespace http;

get('/hello', function() {
   echo "Hello, world!"
});

Hmm… weekend project, perhaps?