# Making PHP composable and look functional

I've found myself on numerous occasions needing to with large text-files, where joining this on that, and filtering this out on arbitrary conditions.

The first couple of times, this turned into a loop in a loop in a loop mess which was indented more times than I care to either remember or admit.

More recently, I've attempted to make something that looks and behaves more "functional". Below is the basic class and a simple example.

I'm primarily concerned with extensibility. I'm not sure the approach I use will lend itself to extensibility in the future. I though, for example, about trying to stream results to disc, and I'm not sure that's doable at all without a fundamental change. Similarly it would be useful to add a simple ->not() for negating a filter, which I also don't see easily doable here.

A secondary concern is performance. PHP is perhaps not the best choice for a functional style. I'm guessing the performance of all these function calls isn't fantastic. Anything obvious I can do to improve it? If "real" performance is a requirement, the obvious suggestion might just to be to not use PHP, but if there are cheap ways to stretch this further, it would be nice.

Code:

class Functional {
protected $result; protected$extra_data;

public function __construct($array = NULL) {$this->result = $array; } public function reduce($callback, $i = NULL) { if ($i === NULL) {
$i =$this->result;
}

$result = array_reduce($i, $callback);$this->result = $result; return$this;
}

public function walk($callback,$i = NULL) {
if ($i === NULL) {$i = $this->result; } array_walk($i, $callback);$this->result = $i; return$this;
}

public function filter($callback,$i = NULL) {
if ($i === NULL) {$i = $this->result; }$this->result = array_filter($i,$callback);
return $this; } public function result() { return$this->result;
}

public function gather($callback,$key) {
$this->extra[$key] = $callback($this->result)
return $this; } public function extra($key) {
return $this->extra[$key];
}
}


Example usage:

$a = [1, 2, 3, 4];$f = new Functional($a);$result = $f->walk(function(&$i) { return $i *= 2; }) ->reduce(function($i, $j) { return$i + $j; }) ->result(); var_dump($result);

int(20)

• whenever a function expects a function as an argument, it'd be best to add the callable type-hint. All in all, I'd also say that you're taking a tool (PHP), and try to use it as something it's not (ie a functional language). You can sort of pull this off, but it's not the best thing to do, IMHO. Using JS, or Scheme, or Haskell would be my advice – Elias Van Ootegem Dec 8 '14 at 15:43
• Hmm, that's a good point... It wasn't available until PHP 5.4 though, right? Sadly I still need it to work in PHP 5.3 as well, despite it's EOL status. I do utilize 5.4 features in the tests (which aren't posted), but I'm avoiding that in the main code for now. – Letharion Dec 8 '14 at 15:44
• Well, if it performance is an issue and if you need to convince anyone to upgrade: moving to PHP 5.5 easily gives you a 20~30% performance boost, possibly more (after upgrading, we saw an increase of well over 25%) – Elias Van Ootegem Dec 8 '14 at 15:50
• As from what I have learned, in functional programming each function only depends on its own arguments and on nothing more. Can a function utilizing $this-> be a part of functional programming? – feeela Dec 8 '14 at 15:51 • @feeela I assume you are thinking of pure functions. I titled the question "look functional", because I'm aware that it won't be pure. – Letharion Dec 8 '14 at 16:41 ## 1 Answer I propose you a more compact version with code duplication removal: You can compact all of your call with an apply method, as shown in the following code: <?php class Functional { protected$result;
protected $extra_data; public function __construct($array = NULL)
{
$this->result =$array;
}

protected function apply($fn,$callback, $value) {$input = (is_null($value)) ?$this->result : $value; call_user_func($fn, $input,$callback);
return $this; } public function reduce($callback, $i = NULL) { return$this->apply('array_reduce', $callback,$i);
}

public function walk($callback,$i = NULL)
{
return $this->apply('array_walk',$callback, $i); } public function filter($callback, $i = NULL) { return$this->apply('array_filter', $callback,$i);
}

public function result()
{
return $this->result; } public function gather($callback, $key) {$this->extra[$key] =$callback($this->result); return$this;
}

public function extra($key) { return$this->extra[\$key];
}
}