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对象被分配一个或多个“处理”回调,这些回调将按顺序调用以执行延迟的任务。

Deferred创建一个Promise,在构造时使用,用于表示延迟任务完成的最终结果。

为了使类与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的承诺实现(reactphp的承诺实现)以及Domenic Denicola出色的写作(Domenic Denicola的出色写作)所带来的巨大工作和灵感。