When I first began using PHP I found it, like many other languages, annoyingly inexpressive. Once you have used Lisp, Haskell, and friends, it is often hard to go back (as Paul Graham observes in the early chapters of On Lisp). Over time, I have begun to discover ways, many of which are documented in the PHP manual, but not in common online tutorials (which are, I would guess, the most common way people learn the language) to use PHP in ways that are at least a little more powerful than the standard procedural spaghetti-code that is traditional in PHPland. This post is about those methods.

Note: This is for versions of PHP < 5.3 which should, if I understand correctly, add support for closures and lambdas.

First, pseudo-function passing. Interestingly enough, PHP has, for a long time, included a way to dynamically use or call functions in a way that is a mere shadow of lambdas and closures. Despite its limited scope and power, it is still better than nothing. You can dynamically call functions using the following syntax:

function foo($a)
{
     return strtoupper($a);
}

function baaz($a)
{
     return strtolower($a);
}

$bar = 'foo';
echo $bar('t'); // will echo 'T'
$bar = 'baaz');
echo $bar('T'); // will echo 't'

Basically, PHP expands the variable into the name of the function before making a call. Again, these aren't first class functions. We are not dynamically creating them or even really passing them. It is more akin to C++ macros (though not quite, as these expand at runtime rather than compiletime) than lambda functions. Interestingly, PHP does not stop there. This expansion can go several layers.

$a = 'foobar!';
$b = 'a';
echo $$b; // will echo 'foobar!'

In this sense, the '$' sigil can almost be seen as 'dereferencing' things, after a fashion. The closest thing PHP has to "real" lambdas is, at present, the create_function function. It works by passing an argument list (as a string) and the function body (again, as a string) and returns a 'reference' to the function. This is, of course, more like the compiler hooks that some languages, like Lisp, offer than true lambdas with all-important closures.

Use arrays like lists. This one does end up feeding off the one above, but is good to mention nonetheless. I can't say I like the choice of term PHP chose for their built-in sequence types. It isn't an array in the C sense. It is actually a hashtable--almost. It would really be a hashtable if anything (including things like objects and functions) could be keys, but instead we are limited to strings and numbers. In practice, this is close enough. Unlike languages like C++ and Java, PHP is not statically typed. This is why we can use arrays as though they were simple sequence types. When we combine this with the function calls as above, we get something nice.

class Quuz
{
   public $something;

   public function __construct($a)
   {
         $this->something = $a;
   }

   public function toString()
   {
        return (string)floatval($this->something / 2);
   }
}

function stringize($foo)
{
    if (is_object($foo))
         return $foo->toString();
    else
         return (string)$foo;
}

$a = array(0 => 'aa', 1 => new Quuz(1));

$b = array_map('stringize', $a);
// $b will equal array(0 => 'aa', 1 => '0.5')

There is one kind of interesting problem I came across with this kind of thing before. You cannot use static methods in some versions of PHP.

In conclusion, it is a shame that bad spaghetti code is so much the norm in the world of PHP. I suppose it is largely a result of the very thing that made it popular: letting novices get up and running quickly. This is, of course, a noble goal. The problem arises when novices suffer stunted growth, remaining forever the script kiddie that unleashed 30,000 line behemoths to run a simple little web site. I hope this article helps ease the pain of stiff PHP for someone out there. In time, I expect this article to be completely obsolete. PHP, like Python, Ruby, and C#, is showing itself a member of a general trend. Namely, that today's languages are starting to import the things we all know and love from the Lisp ecosystem (yeah, that's my term for Lisp, Haskell, OCaml, Standard ML, Scheme, etc. ad nauseum) and make them available to the working programmer. In the meantime, this is how I ease the pain.