我如何 "extract" 来自 ReactPHP\Promise\Promise 的数据?

How do I "extract" the data from a ReactPHP\Promise\Promise?

免责声明:这是我第一次使用 ReactPHP 和 "php promises",所以解决方案可能只是盯着我看

我目前正在做一个小项目,我需要在其中创建一个 Slack 机器人。我决定使用 Botman 包并利用它的 Slack RTM 驱动程序。此驱动程序利用 ReactPHP 的承诺与 RTM API.

进行通信

我的问题:

当我让机器人回复命令时,我想从 RTM API 获取响应,这样我就可以缓存发布消息的 ID。

问题是,响应正在其中一个内部返回 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(),这就是(据我所知)official ReactPHP docs suggest you should use to retrieve data from a promise:

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

但是 $response returns 为 null.

有趣的是,在调试期间,我试图在 then() 中执行 var_dump($item) 但忘记删除 promise 上不存在的方法。但是 var_dump 实际上返回了数据

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

所以据我所知,我似乎需要再次 "execute" 承诺,即使它在返回之前已经解决。

在 Bot 的回复方法中,这是正在发生的事情以及 ReactPHP promise 是如何生成的:

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

您可以查看它的完整源代码here

请给我指明方向。我觉得我尝试了一切,但显然我遗漏了什么或做错了什么。

ReactPHP 核心团队成员在这里。这里有一些选项和事情。

首先 then 永远不会 return 承诺的价值,它会 return 一个新的承诺,这样你就可以创建一个承诺链。因此,您在每个 then 中执行一个新的异步操作,该操作接收前一个的结果。

其次,done 永远不会 return 的结果值并且工作方式与 then 非常相似,但会抛出链中先前承诺的任何未捕获异常。

thendone 的问题在于它们是您的解决方法。承诺 a 仅表示尚未完成的操作的结果。一旦操作准备就绪并解决承诺,它将调用您交给 then/donecallable。因此,最终您的所有操作都在 callable 中以一种或另一种方式发生,并且在最广泛的意义上。 (这也可以是 class 上的 __invoke 方法,具体取决于您的设置方式。还有为什么我对 PHP 7.4 中出现的短闭包如此兴奋.)

这里有两个选择:

  • 运行 您在 callable
  • 中的所有操作
  • 使用RecoilPHP

前者意味着更多的思维导图和学习异步的工作原理以及如何围绕它进行思考。后者使它更容易,但需要您 运行 协程中的每个路径(callable 一些很酷的魔法)。