Как «извлечь» данные из ReactPHP \ Promise \ Promise? - PullRequest
2 голосов
/ 13 июня 2019

Отказ от ответственности: я впервые работаю с ReactPHP и "php promises", поэтому решение может просто смотреть мне в лицо ?

Я сейчас работаюна небольшом проекте, где мне нужно создать бот Slack.Я решил использовать пакет Botman и использовать его драйвер Slack RTM.Этот драйвер использует обещания ReactPHP для связи с RTM API.

Моя проблема:

Когда я отвечаю ботом на команду, я хочу получить get getответ от RTM API, так что я могу кэшировать идентификатор отправленного сообщения.

Проблема в том, что ответ возвращается внутри одного из этих ReactPHP\Promise\Promise, но я просто не могу понять, как получитьданные.

Что я делаю:

Поэтому, когда команда запускается, бот отправляет ответ Slack:

$response = $bot->reply($response)->then(function (Payload $item) {
    return $this->reply = $item;
});

Но тогда $response состоит из (пусто?) ReactPHP\Promise\Promise:

React\Promise\Promise^ {#887
  -canceller: null
  -result: null
  -handlers: []
  -progressHandlers: & []
  -requiredCancelRequests: 0
  -cancelRequests: 0
}

Я также пытался использовать done() вместо then(), что и есть (насколько я понимаю) официальные документы ReactPHP предлагают использовать для получения данных из обещания :

$response = $bot->reply($response)->done(function (Payload $item) {
    return $this->reply = $item;
});

Но тогда $response возвращается как null.

ЗабавноДело в том, что во время отладки я пытался выполнить var_dump($item) внутри then(), но забыл удалить несуществующий метод в обещании.Но затем var_dump фактически вернул данные ?

$response = $bot->reply($response)->then(function (Payload $item) {
    var_dump($item);
    return $this->reply = $item;
})->resolve();

Итак, из того, что я могу понять, я как-то должен снова «выполнить» обещание, даже если оно было решено до его возвращения.

Внутри метода ответа бота, это то, что происходит и как генерируется обещание ReactPHP:

public function apiCall($method, array $args = [], $multipart = false, $callDeferred = true)
{
    // create the request url
    $requestUrl = self::BASE_URL . $method;

    // set the api token
    $args['token'] = $this->token;

    // send a post request with all arguments
    $requestType = $multipart ? 'multipart' : 'form_params';
    $requestData = $multipart ? $this->convertToMultipartArray($args) : $args;

    $promise = $this->httpClient->postAsync($requestUrl, [
        $requestType => $requestData,
    ]);

    // Add requests to the event loop to be handled at a later date.
    if ($callDeferred) {
        $this->loop->futureTick(function () use ($promise) {
            $promise->wait();
        });
    } else {
        $promise->wait();
    }

    // When the response has arrived, parse it and resolve. Note that our
    // promises aren't pretty; Guzzle promises are not compatible with React
    // promises, so the only Guzzle promises ever used die in here and it is
    // React from here on out.
    $deferred = new Deferred();
    $promise->then(function (ResponseInterface $response) use ($deferred) {
        // get the response as a json object
        $payload = Payload::fromJson((string) $response->getBody());

        // check if there was an error
        if (isset($payload['ok']) && $payload['ok'] === true) {
            $deferred->resolve($payload);
        } else {
            // make a nice-looking error message and throw an exception
            $niceMessage = ucfirst(str_replace('_', ' ', $payload['error']));
            $deferred->reject(new ApiException($niceMessage));
        }
    });

    return $deferred->promise();
}

Вы можете увидеть его полный источник здесь .

Пожалуйста, просто укажите мне в каком-то направлении.Я чувствую, что попробовал все, но, очевидно, я что-то упускаю или делаю что-то не так.

1 Ответ

1 голос
/ 13 июня 2019

Член основной команды ReactPHP здесь.Здесь есть несколько вариантов и вещей.

Прежде всего then никогда не вернет значение из обещания, оно вернет новое обещание, чтобы вы могли создать цепочку обещаний.В результате вы выполняете новую асинхронную операцию в каждой из них, которая получает результат от предыдущей.

Во-вторых done никогда не возвращает значение результата и работает почти так же, как then, но выдает любуюuncaught исключения из предыдущего обещания в цепочке.

С обоими then и done дело в том, что они ваши методы разрешения.Обещание просто представляет собой результат операции, которая еще не выполнена.Как только операция будет готова, она вызовет callable, которую вы передадите, then / done и выполнит обещание.Таким образом, в конечном итоге все ваши операции происходят внутри callable так или иначе и в самом широком смысле.(Который также может быть методом __invoke в классе в зависимости от того, как вы его настроили. А также почему я так рад появлению коротких замыканий в PHP 7.4.)

У вас есть два вариантаздесь:

  • Выполните все свои операции внутри callable
  • Использование RecoilPHP

Первое означает намного большесоставление карт разума и изучение того, как работает асинхронность и как обдумать это.Последнее облегчает задачу, но требует от вас прохождения каждого пути в сопрограмме (callable с помощью некоторой крутой магии).

...