Phpinspectionsea: Report usage of anonymous functions as argument

Created on 27 Mar 2017  路  2Comments  路  Source: kalessil/phpinspectionsea

_Just a note: it's a bit different of #210, but will cross in some moment._

Basically, it should report to you the usage of anonymous functions as argument to a function or method that expects a callable.

Case 1

$reduced = array_reduce($array, function ($carry, $input) {
    return $carry + $input;
});

In this case, is better you create a specific function (helper) that will do that for you. It'll avoid duplicated, _hard-to-test_ code and will improve the readability of current code.

How to fix:

$reduced = array_reduce($array, [ ReduceHelper::class, 'sumInputs' ]);

Optionally you can return an anonymous function from the helper, but in this case, it is not need. The next case will be better for that.

Case 2

Ok, then let's supposes that you need pass some variables with use(). Then you should do that by creating a function that return an anonymous function. I guess that it should solve the problem and keep the function testeable.

I'll give a more complex example, just for show that it's possible and viable.

$array = [ 1, 2, 3, 4, 5 ];
$factor = 2;

echo array_reduce($array, function ($carry, $input) use (&$factor) {
    $factor *= 0.8;
    return $carry + ( $input * $factor);
});

How to solve:

First, implements a new method on helper, that do exactly the samething, but returning an anonymous function that could be tested by somekind of ReduceHelperTest:

static public function sumInputsWithFactor(&$factor)
{
    return function ($carry, $input) use (&$factor) {
        $factor *= 0.8;
        return $carry + ($input * $factor);
    };
}

Then update your call:

$array = [ 1, 2, 3, 4, 5 ];
$factor = 2;

echo array_reduce($array, ReduceHelper::sumInputsWithFactor($factor));

If you do right, then you will get 13.7856 as output and $factor will be updated to 0.65536.

enhancement wontfix

Most helpful comment

What would actually be better is a delegate class:

final class Reducer {
    private $factor;

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

    public function __invoke(int $carry, int $input): int {
        $this->factor *= .8;

        return $carry + ($input * $this->factor);
    }

    public function getFactor(): int {
        return $this->factor;
    }
}

Now we have type safety and can pass it to array_reduce:

$array = [1, 2, 3, 4, 5];
$reducer = new Reducer(2);

echo \array_reduce($array, $reducer);
echo $reducer->getFactor();

All 2 comments

What would actually be better is a delegate class:

final class Reducer {
    private $factor;

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

    public function __invoke(int $carry, int $input): int {
        $this->factor *= .8;

        return $carry + ($input * $this->factor);
    }

    public function getFactor(): int {
        return $this->factor;
    }
}

Now we have type safety and can pass it to array_reduce:

$array = [1, 2, 3, 4, 5];
$reducer = new Reducer(2);

echo \array_reduce($array, $reducer);
echo $reducer->getFactor();

Bebo beep, the StaleBot is here. For one year nothing have happened here. It would be great if someone looked into details here within next 21 days when I'll close it.

Was this page helpful?
0 / 5 - 0 ratings