PHP - nagate callback result

111 Views Asked by At

Is there any way to negate result of callback?

$this->myInjectedService->doSomething([$this, 'myCallback']);

I need to nagate result of myCallback method. I know I can do it by nested function, but is there any more clean way (exclamation mark)?

$this->myInjectedService->doSomething(function() {
    return !$this->myCallback();
});
1

There are 1 best solutions below

0
On BEST ANSWER

No, there is no direct way to do it like that.

What you could do, would be to create a callback wrapper which negates the callback you want to call. Every time you want to negate a callback you can use that wrapper instead of the callback itself:

<?php

class SomeService
{
    public function doSomething(callable $callback)
    {
        return call_user_func($callback);
    }
}

final class CallbackWrapper
{
    public static function call(callable $callback, bool $negate = false): callable
    {
        if ($negate) {
            return function() use ($callback) {
                return !call_user_func($callback);
            };
        }

        return $callback;
    }
}

class Test
{
    public function __construct()
    {
        $this->someService = new SomeService();
    }

    public function doSomething()
    {
        // Scenario 1: use direct callback
        $result = $this->someService->doSomething([$this, 'thisIsACallback']);

        var_dump($result);

        // Scenario 2: use wrapper without negating
        $result = $this->someService->doSomething(
            call_user_func_array('CallbackWrapper::call', [[$this, 'thisIsACallback']])
        );

        var_dump($result);

        // Scenario 3: use wrapper with negation
        $result = $this->someService->doSomething(
            call_user_func_array('CallbackWrapper::call', [[$this, 'thisIsACallback'], true])
        );

        var_dump($result);
    }

    public function thisIsACallback(): bool
    {
        return true;
    }
}

$test = new Test();
$test->doSomething();

The results would be:

// Scenario 1
bool(true)

// Scenario 2
bool(true)

// Scenario 3
bool(false)

Please note that this is the simplest approach I could think of, but if you need more complex callbacks to be called then you might need to update the wrapper.

PS: Even if it's possible, I don't recommend using this approach, as using a nested function, as you already did, is much more clear and easier to read/understand.