phpgt/promise

愉快地处理异步代码。

维护者

详细信息

github.com/PhpGt/Promise

源代码

问题

资助包维护!
PhpGt

v2.2.3 2023-07-01 10:59 UTC

README

关于Promise概念有许多实现。这个库旨在与Web API的Promise实现兼容,提供与在浏览器中处理Promise时相同的thencatchfinally机制。

Build status Code quality Code coverage Current version PHP.Gt/Promise documentation

在计算机科学中,Promise是一种机制,它提供了程序性代码与异步回调之间简单直接的关系。在程序性语言中,如传统的PHP,函数有两种方式可以影响程序的流程:要么返回值,要么抛出异常。

当处理执行异步的函数时,我们无法返回值,因为它们可能还没有准备好,我们也无法抛出异常,因为这是一个程序性概念(我们应当在何处捕获它们?)。这就是Promise的作用所在:不是返回值或抛出异常,你的函数可以返回一个Promise,这是一个对象,可以被一个值履行,或被一个异常拒绝,但并不一定是在它们返回的时候。

使用这个概念,实际计算或加载代码所需值的任务可以被延迟到执行异步的任务中。在PHP.Gt/Promise的背后,有一个用于此目的的Deferred类。

示例用法

以下是这个库提供的语法示例。

// A simple operation with just a single "then":
$exampleSlowFileReader->read()
->then(function(string $contents) {
        echo "Contents of file: $contents", PHP_EOL;
});

// A more complex example, showing how promises can be chained together:
$exampleRemoteApi->getCustomerById(105)
->then(function(Customer $customer) {
        return $customer->loadLatestOrders(new DateTime("-5 weeks"));
})
->then(function(CustomerOrderList $orders) {
        echo "Customer {$orders->getCustomer()->getName()} ",
        "has made {count($orders)} in the last 5 weeks!", PHP_EOL;
})
->catch(function(Throwable $reason) {
        echo "There was an error loading the customer's details: $reason", PHP_EOL;
})
->finally(function() use($exampleRemoteApi) {
        $exampleRemoteApi->disconnect();
});

DeferredPromise 对象

这个仓库将异步任务的处理责任和任务完成的输出分别分配给了DeferredPromise类。

Deferred对象分配了一个或多个“处理”回调,这些回调将被按顺序调用以执行延迟任务。

Promise在构造时由Deferred创建,用于表示延迟任务完成的输出。

为了使类与Promise一起工作,它至少需要两个函数:一个公共函数,用于构建Deferred对象并返回Promise,以及一个作为Deferred处理函数分配的函数。

请参阅下面的示例代码布局

class Example {
// The class must keep a reference to its own Deferred object, as this will be
// referenced when the work completes in order to resolve its Promise.
        private Deferred $deferred;

// This public function will return a Promise representing the task's outcome.
        public function doTheTask():PromiseInterface {
// The Deferred is constructed with the process function as its only parameter.
                $this->deferred = new Deferred(fn() => $this->processFunction());
// The function returns the Deferred's promise.
                return $this->deferred->getPromise();
        }

// The process function will do one small piece of work each time it's called
// until the task is complete, at which point it will resolve the Deferred with
// the final value (from wherever it's calculated).
        private function processFunction():void {
                if($this->isThereMoreWorkToDo()) {
                        $this->doMoreWork();
                }
                else {
                        $this->deferred->resolve($this->getFinalValue());
                }
        }

        private function isThereMoreWorkToDo():bool { /* ... */ }
        private function doMoreWork():void { /* ... */ }
        private function getFinalValue() { /* ... */ }
}

上述示例类如何整合的最简单表示如下

$example = new Example();
$example->doTheTask()
->then(function($finalValue) {
        echo "Final value: ", $finalValue;
});

最终结果是能够调用公共函数,而不需要了解Promise/Deferred实现。

重要提示:PHP仍然是一种完全的程序性语言,因此,如果没有使用外部循环来调用延迟处理,Promise永远不会履行或拒绝。

事件循环

为了使这个Promise库有用,必须有某些代码充当事件循环来调用延迟过程。这可以是一个简单的while循环,但在现实世界的任务中,应该使用更全面的循环系统。

基于Promise的架构实现本身就足够复杂,因此事件循环库的责任被单独维护在PHP.Gt/Async中。

特别感谢

这个仓库的开发工作主要归功于reactphp的Promise实现和Domenic Denicola出色的写作所带来的巨大工作和灵感。