Kontaktieren Sie uns: +49 (711) 46 97 28 - 80|info@teqneers.de

Closures are functions with state

A closure is a programming language concept that combines a function with a reference to an environment during creation time of the function – or simply put: a function combined with some state. But we’ve heard something similar when people talk about objects in programming languages, haven’t we? An object is state combined with functions. So are they interchangeable? Well, up to a certain degree, I’d say, yes. There are use-cases where closures and objects can be used interchangeably and we’ll look into one of them.

Take a simple example. We have a simple list of employees together with their salary:

$list = array(
    array('name' => 'Blake', 'salary' => 35000),
    array('name' => 'Sakic', 'salary' => 75000),
    // ...
);

The task is to provide a mechanism to filter the list by a configurable criteria on the salary column. Taking an object-oriented approach one might start with:

interface SalaryFilter {
     public function filter(array $employee);
}

class SalaryLessThanFilter implements SalaryFilter {
    private $limit;
    public function __construct($limit) {
        $this->limit = (int)$limit;
    }
    public function filter(array $employee) {
        return $employee['salary'] < $this->limit;
    }
}

class SalaryMoreThanFilter implements SalaryFilter {
    private $limit;
    public function __construct($limit) {
        $this->limit = (int)$limit;
    }
    public function filter(array $employee) {
        return $employee['salary'] > $this->limit;
    }
}

class SalaryBetweenFilter implements SalaryFilter {
    private $limitA;
    private $limitB;
    public function __construct($limitA, $limitB) {
        $this->limitA = (int)$limitA;
        $this->limitB = (int)$limitB;
    }
    public function filter(array $employee) {
        return $employee['salary'] > $this->limitA
               && $employee['salary'] < $this->limitB;
    }
}

A simple generic filter function (I know, I know – I said object-oriented approach, but that does not require us to refrain from using regular functions altogether) will allow us to filter the array with any of the available filters.

function filter(array $list, SalaryFilter $filter) {
    return array_filter($list, array($filter, 'filter'));
}

// for example
print_r(filter($list, new SalaryLessThanFilter(70000)));
print_r(filter($list, new SalaryMoreThanFilter(70000)));
print_r(filter($list, new SalaryBetweenFilter(30000, 80000)));

We have now built a very simple implementation of the so called strategy pattern – the possibility to exchange an algorithm during runtime. This is not perfect for sure but it’s an example simple enough to show the similarities between closures and objects.

The „closure“ approach on the other hand might look like this:

function salaryLessThan($limit) {
    return function(array $employee) use ($limit) {
        return $employee['salary'] < $limit;
    };
}

function salaryMoreThan($limit) {
    return function(array $employee) use ($limit) {
        return $employee['salary'] > $limit;
    };
}

function salaryBetween($limitA, $limitB) {
    return function(array $employee) use ($limitA, $limitB) {
        return $employee['salary'] > $limitA
               && $employee['salary'] < $limitB;
    };
}

This is way less code than the original object-oriented approach is required and the filter function is even simpler:

function filter(array $list, callable $filter) {
    return array_filter($list, $filter);
}

print_r(filter($list, salaryLessThan(70000)));
print_r(filter($list, salaryMoreThan(70000)));
print_r(filter($list, salaryBetween(30000, 80000)));

Extending these simple list of algorithms is also much simpler now because we’re not limited to classes implementing the SalaryFilter interface. We can use whatever callable we like.

<aside>

We can even make our original implementation compatible with the new approach, by the way, using the __invoke() magic method PHP provides.

interface SalaryFilter {
     public function filter(array $employee);
     public function __invoke(array $employee);
}

class SalaryLessThanFilter implements SalaryFilter {
    //...
    public function __invoke(array $employee) {
        return $this->filter($employee);
    }
}

class SalaryMoreThanFilter implements SalaryFilter {
    //...
    public function __invoke(array $employee) {
        return $this->filter($employee);
    }
}

class SalaryBetweenFilter implements SalaryFilter {
    //...
    public function __invoke(array $employee) {
        return $this->filter($employee);
    }
}

print_r(filter($list, new SalaryLessThanFilter(70000)));
print_r(filter($list, new SalaryMoreThanFilter(70000)));
print_r(filter($list, new SalaryBetweenFilter(30000, 80000)));

</aside>

Let’s do a quick discussion of what we’ve seen so far. Starting from a „traditional“ object oriented approach, we interchanged classes and objects with closures in a completely functional approach but kept the overall concept of the strategy pattern intact. Our closures just carry their „state“ (which is the filter limit(s)) and the algorithm (which is the comparison logic) with them to be moved around our code. Basically the same way as objects created from our filter classes carry their algorithm (the class method filter) and their state (the limit property) around. We can now say that in this given example objects and closure are interchangeable and that closures require far less code than a traditional approach in our case.

That’s why closures really can make sense with simple strategy-pattern-like code that requires algorithms to be configurable and exchangeable. Use cases might be sorting, filtering, calculation, etc. Just always use the right tool for the job and object-oriented and functional approaches go together quite well, I think,

By | 2013-09-10T16:04:11+00:00 September 10th, 2013|Development|0 Comments

Leave A Comment