No? I suspect you're not alone. Nevertheless, I've written this article to show you how to do just that using reflection and closures in PHP.

But first, a little background

Closures, also known as anonymous functions, have been with us since PHP5.3 and for sure, there are a few resources out there on the Internet that will give you an idea of what they're all about.

As you might deduce from the term, anonymous functions are functions without a name. Here's an example.

$anon = function($name) {
  print "Hello {$name}";
}

$anon('Fred');

// Output
$ Hello Fred

Granted, it's a very simplistic example but it does at least show you how we've created a function and immediately assigned it to the $anon variable.

Cherry picking methods

One thing that you don't often see, however, is the practice of cherry picking an existing method from an object instance and using it as an independent function. To illustrate this idea, take a look at the following example code:

First of all, let's set up a simple class and instantiate an object from it.

<?php
class Character
{
  private $name;

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

  public function getName()
  {
    return $this->name;
  }
}

$kyloRen = new Character("Kylo Ren");
?>

So far, so good. We have an exceedingly basic Character class and have created a "Kylo Ren" instance from it.

Our next step is to cherry pick that getName() method out of the object instance and assign it to a variable. This is done in two stages.

First of all, we will use reflection to create a reflected copy of the method that we are interested in.

$reflectedMethod = new ReflectionMethod($kyloRen, "getName");

If all is well, our $reflectedMethod variable is now an instance of the ReflectionMethod class (see the manual page here).

If you glance down the list of methods that this class provides, you'll notice that one of them is called getClosure. This is the one that we're interested in, so let's pick up the closure now.

$closure = $reflectedMethod->getClosure($kyloRen);

Whilst the manual is woefully short on detail here, what we are doing is effectively turning the original getName() method into an anonymous function. But do note that I'm passing the original source object in as a parameter. I'm doing this to maintain the original scope for the method itself.

If we wanted to check it, we can do so easily with the following line of code

echo $closure();

// Output
$ Kylo Ren

As with all functions, the way to invoke our closure here is the suffix the variable with the opening and closing parentheses.

Great, so now we have a slightly useless anonymous function assigned to a variable. The interesting thing to note though is that the scope of the function is still bound to the original source instance.

Making a monster

On its own, a closure created in this way is surprisingly useful in that it allows you to pull out a live method from an object instance as use it as a hook back to that object instance.

But this article is about building a monster by attaching methods scavenged from other object instances onto a skeletal frame that we can use as a hybrid.

So, let's take a look at our skeleton class

class Skeleton
{
  private $methods = [];

  public function addMethod($methodName, Callable $func)
  {
    $this->methods[$methodName] = $func;
    return $this;
  }

  public function __call($methodName, $args)
  {
    return call_user_func_array($this->methods[$methodName], $args);
  }
}

This skeleton class provides the basis for our monster; the underlying frame that we can flesh out with methods scavenged from other objects. For example, we can add the getName() method from our previous example to our newly instantiated monster like this.

$monster = new Skeleton();
$monster->addMethod('getName', $closure);

Does it work? Sure it does. Here's the code to prove it.

echo $monster->getName();

// Output
$ Kylo Ren

Thanks to the magic __call() method included within our skeleton, we can now invoke the getName() method that we originally copied from our Character instance by calling it on our monster instance.

Going forward, we can keep scavenging methods from a variety of object instances and attaching them to the skeleton, with each scavenged method providing a link back to the original instance.

What use is this?

Well, it's a very good question but for starters, I can imagine a scenario where plucking the methods of a number of model objects and attaching them to a single skeleton to be represented in a view makes for an interesting way to create a "read only" gateway to a collection of application data.

Links

I've provided a quick and dirty package on github if you fancy tinkering around with the code. Get it here: vanqard/frankenbuilder.

This topic was also discussed in the chapter on Closures from my book, PHP Brilliance

Questions? Comments? Let me know in the comment section below. And thank you for reading.