3 Cool Things You Can Do With Arrays In PHP

PHP has a wide variety of functions for interacting with arrays. Some of them are more known than others. In this short blog, I will demonstrate 3 cool things you can do with arrays in PHP that you may or may not know about.

Turn variables into arrays

The first thing I want to show is how to use compact() to turn variables into an array. I never heard of it before using Laravel, but now I use it all the time – especially in my controllers when I need to pass variables to a view.

php > $name = 'Peter';
php > $email = 'peter@suhm.dk';
php > $array = compact('name', 'email');
php > var_dump($array);
array(2) {
  ["name"]=>
  string(5) "Peter"
  ["email"]=>
  string(13) "peter@suhm.dk"
}

Turn arrays into variables

The opposite of compact() is extract(), which lets you turn an array into a bunch of variables.

php > $array = array('name' => 'Peter', 'email' => 'peter@suhm.dk');
php > extract($array);
php > var_dump($name);
string(5) "Peter"
php > var_dump($email);
string(13) "peter@suhm.dk"

Implement ArrayAccess

Finally, I want to demonstrate the ArrayAccess interface that comes with PHP. It is really awesome and lets you take arrays to the next level. If you need inspiration, check out the Collection class from Laravel. By implementing ArrayAccess, your objects can be accessed like they were an array, which is pretty awesome.

class AwesomeClass implements ArrayAccess
{
    // Example from php.net
    // http://php.net/manual/en/class.arrayaccess.php
    private $container = [];

    public function offsetSet($offset, $value) {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset) {
        return isset($this->container[$offset]);
    }

    public function offsetUnset($offset) {
        unset($this->container[$offset]);
    }

    public function offsetGet($offset) {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }
}

// Usage
$awesome = new AwesomeClass;

$awesome['name'] = 'Peter';

Resolving Controllers With Symfony And A DI Container

For a project I am working on at the moment, we are using Symfony’s great routing component. The other day, I had to set up the routes to work together with our controllers and stumbled upon something that I would like to document here.

By adding a _controller parameter, such as ‘PostsController::show‘, to a route, Symfony’s ControllerResolver can automatically resolve the controller class given a request object. The ControllerResolver is a part of the HttpKernel component, and also contains an interface, so you can implement it however you like. In my particular case, I actually needed to resolve the class from my DI container, and only needed the resolver to resolve the arguments of the method. I was not going to implement my own ControllerResolver, so here is what I did instead:

// First, fetch the controller string from the request
// Could be something like 'PostsController::show'
$controllerString = $app->request->attributes->get('_controller');

// Next, split the controller string and pass it to two variables
list($class, $method) = explode('::', $controllerString);

// Resolve the controller class out of the DI container
$controller = $app->get($class);

// And use the ControllerResolver to get the arguments
// of the method
$resolver = new ControllerResolver();
$arguments = $resolver->getArguments(
    $app->request,
    [$class, $method]
);

// Now that we have the class and the arguments, we
// can finally call the controller and have it return a response
$response = call_user_func_array(
    [$controller, $method],
    $arguments
);

Recursively Resolving Dependencies With PHP’s Reflection API (Part 1)

Today’s post have a very long title, even though the actual concept we are going to discuss is quite simple and straightforward. The whole concept of dependency injection can sound very complicated, but it really isn’t.

This is dependency injection:

class UserManager
{
    protected $users;

    public function __construct(UserRepository $users)
    {
        $this->users = $user;
    }
}

The UserManager depends on a UserRepository, which we therefore inject through the constructor. This has some obvious advantages – especially if we make our objects dependent on interfaces instead of implementations. We will get back to this in part 2.

Resolving dependencies

How do we resolve the dependencies of our objects, so we can properly instantiate them? This can be quite cumbersome.

Instantiating an object with its dependencies:

$userManager = new UserManager(
    new UserRepository(
        new EntityMapper(
            new DB(
                new Configuration()
))));

You get the point. The dependencies has dependencies themselves.

We need to automate this, and actually, automatic dependency resolution is a core part of modern PHP frameworks such as Laravel. Lately, though, I have been working on several legacy codebases (I consider WordPress legacy as well), where some sort of automatic resolution comes in very handy. In legacy projects, oftentimes there is no easy way to access different objects across the codebase (global variables, I’m looking at you!). Implementing some sort of service container that can help me resolve services and their dependencies is always one of the first things I do. And the good news is, with PHP’s reflection API, this is not too hard to implement.

Here is what the PHP documentation says about reflection:

PHP 5 comes with a complete reflection API that adds the ability to reverse-engineer classes, interfaces, functions, methods and extensions.

In short, the reflection API gives us an easy way to gather information about our classes and objects (including their dependencies), which is exactly what we need to implement our own dependency resolution mechanism.

Ultimately, this is what we want:

$userManager = $container->resolve('UserManager');
// UserManager instance, including all nested dependencies

Let’s see some code:

class Container
{
    public function resolve($class)
    {
        // Reflect on the $class
        $reflectionClass = new ReflectionClass($class);

        // Fetch the constructor (instance of ReflectionMethod)
        $constructor = $reflectionClass->getConstructor();

        // If there is no constructor, there is no
        // dependencies, which means that our job is done.
        if ( ! $constructor)
            return new $class;

        // Fetch the arguments from the constructor
        // (collection of ReflectionParameter instances)
        $params = $constructor->getParameters();

        // If there is a constructor, but no dependencies,
        // our job is done.
        if (count($params) === 0)
            return new $class;

        // This is were we store the dependencies
        $newInstanceParams = [];

        // Loop over the constructor arguments
        foreach ($params as $param) {

            // Here we should perform a bunch of checks, such as:
            // isArray(), isCallable(), isDefaultValueAvailable()
            // isOptional() etc.

            // For now, we just check to see if the argument is
            // a class, so we can instantiate it,
            // otherwise we just pass null.
            if (is_null($param->getClass())) {
                $newInstanceParams[] = null;
                continue;
            }


            // This is where 'the magic happens'. We resolve each
            // of the dependencies, by recursively calling the
            // resolve() method.
            // At one point, we will reach the bottom of the
            // nested dependencies we need in order to instantiate
            // the class.
            $newInstanceParams[] = $this->resolve(
                $param->getClass()->getName()
            );
        }

        // Return the reflected class, instantiated with all its
        // dependencies (this happens once for all the
        // nested dependencies).
        return $reflectionClass->newInstanceArgs(
            $newInstanceParams
        );
    }
}

With the resolve() method, we can achieve something like this:

php > $userManager = $container->resolve('UserManager');
php > var_dump($userManager);
class UserManager#7 (1) {
  protected $users =>
  class UserRepository#10 (1) {
    protected $em =>
    class EntityMapper#13 (1) {
      protected $db =>
      class DB#14 (1) {
        ...
      }
    }
  }
}

This works because of the recursive behaviour of the method. According to Wikipedia, recursion:

… refers to a method of defining functions in which the function being defined is applied within its own definition.

The above definition basically means that a function calls itself. In our case, the resolve() method calls itself with each dependency it discovers as a parameter. We do not want dependencies to depend on each other, in which case we would have a recursive loop that would never end. Object #1 would require object #2 that would require object #1 and so on. Dependencies should only go one way, so we know that our recursive dependency resolution mechanism will eventually hit the bottom of the dependency tree.

That was a lot of fancy words for a simple concept, but I hope you get the idea. The PHP reflection API is fun to play around with and indeed very useful. In the next part, we will take a look at how to allow binding of actual implementations to the service container, so our code can rely on interfaces instead.