PHP - результат обратного вызова - PullRequest
0 голосов
/ 31 марта 2020

Есть ли способ отменить результат обратного вызова?

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

Мне нужно получить результат метода myCallback . Я знаю, что могу сделать это с помощью вложенной функции, но есть ли более чистый способ (восклицательный знак)?

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

1 Ответ

0 голосов
/ 31 марта 2020

Нет, прямого способа сделать это не существует.

Что бы вы могли сделать, это создать оболочку обратного вызова, которая сводит на нет обратный вызов, который вы хотите вызвать. Каждый раз, когда вы хотите отменить обратный вызов, вы можете использовать эту оболочку вместо самого обратного вызова:

<?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();

Результаты будут такими:

// Scenario 1
bool(true)

// Scenario 2
bool(true)

// Scenario 3
bool(false)

Обратите внимание, что это самый простой подход Я мог бы подумать, но если вам нужны более сложные обратные вызовы для вызова, вам может потребоваться обновить оболочку.

PS: даже если это возможно, я не рекомендую использовать этот подход, так как используется вложенный Функция, как вы уже сделали, намного более понятна и легче для чтения / понимания.

...