moebius/promise 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

moebius/promise

Composer 安装命令:

composer require moebius/promise

包简介

A flexible and compatible promise implementation for PHP.

README 文档

README

A pure Promises/A+ promise implementation, designed to be flexible and well tested - and promoting interoperability.

Promise interface

Promise objects have the following clean interface. This interface and implementation follows the ECMAScript Promise Specification as closely as possible. This means that you you can assume that the same semantics you know from javascript will work for these promises.

namespace Moebius;

interface PromiseInterface {

    /**
     * Schedule a callback to run when the promise is fulfilled
     * or rejected.
     *
     * @param callable $onFulfill   Callback which will be invoked if the promise is fulfilled.
     * @param callable $onReject    Callback which will be invoked if the promise is rejected.
     * @param callable $void        Ignored; for compataiblity with other promise implementations.
     * @return PromiseInterface     Returns a new promise which is resolved with the return value of $onFulfill/$onReject
     */
    public function then(callable $onFulfill=null, callable $onReject=null, callable $void=null): PromiseInterface;

    /**
     * Is the promise still pending resolution?
     */
    public function isPending(): bool;

    /**
     * Is the promise fulfilled?
     */
    public function isFulfilled(): bool;

    /**
     * Is the promise rejected?
     */
    public function isRejected(): bool;

}

Interoperability

It is very common for promise-aware PHP libraries to explicitly type-check objects for compatability. This library provides a type-checking functions for this purpose:

Type casting

If you need to ensure that the provided object follows the Promises/A+ semantics, with chainable then() - you should use the Moebius\Promise::cast() method:

use Moebius\Promise;

$promise = Promise::cast($somePromise);

// Now you can safely check if the promise has been resolved

Type checking

use Moebius\Promise;

if (Promise::isPromise($someObject)) {
    // You can treat $someObject as a promise
}

// Type casting $promise = Promise::cast($someObject);

Casting a promise

Promises from other implementations can be cast to Moebius\Promise.

<?php
$promise = Moebius\Promise::cast($otherPromise);

Identifying a promise-like object

Since there is no canonical PHP promise interface, it is useful to have a simple way to check if an object appears to be a valid promise.

<?php
if (Moebius\Promise::isPromise($otherPromise)) {
    // promise has a valid `then()` method
}

Creating a promise

Promises can generally be created in two ways; with a resolver function or without a resolver function - in which case the promise must be resolved by calling the fulfill() or the reject() method.

With a resolver function*

<?php
$promise = new Promise(function(callable $fulfill, callable $reject) {
    $fulfill("Hello World");
});
$promise->then(function($value) {
    echo $value."\n";
});

Without a resolver function

<?php
$promise = new Promise();
$promise->then(function($value) {
    echo $value."\n";
});
$promise->resolve("Hello World");

Interoperability Notes

The interface is focused on the resolution of promises; it does not care about how a promise is created - the interface is for functions that accept a promise.

Most promise implementations have an extensive API, but a promise only needs to expose a then() function to be usable by 90% of libraries.

It is also very helpful to have a way to determine if a promise is already resolved or rejected - which generally is implemented using a method which returns a string "pending", "resolved", "rejected" or "fulfilled".

This library implements methods isPending(), isResolved() and isFulfilled() because these methods can be implemented regardless of how the underlying promise implementation records that state..

Many promise implementations have methods like otherwise(), finally() and similar - which may be convenient, but it reduces interoperability because the same features can be implemented in several ways and with different names.

A promise implementation which is widely compatible with various libraries.

Modelled after the Promises/A+ specification in JavaScript.

If you create a Moebius\Promise instance, it is directly usable as a drop-in replacement for:

  • guzzlehttp/promises by implementing GuzzleHttp\Promise\PromiseInterface
  • react/promise by implementing React\Promise\PromiseInterface
  • 'php-http/promise' by implementing Http\Promise\Promise
  • amphp/amp by implementing Amp\Promise

The Moebius\Promise objects have two primary uses: As a standard Promise object, and as a Deferred object using React terminology.

Basic Promise Usage

This is the most common way to use a promise:

use Moebius\Promise;

function some_future_result() {
    return new Promise(function($fulfill, $reject) {
        /**
         * Either fulfill the promise directly here, by calling
         * the provided $fulfill(VALUE) and $reject(REASON) callbacks
         * immediately, or make sure that one of these are called at
         * a later time.
         */
    });
}

"Deferred" usage

In React and some other libraries, an additional type of promise is called a "deferred" promise. Moebius combines these two uses:

use Moebius\Promise;

function some_future_result() {
    $result = new Promise();

    /**
     * Make sure that the promise is resolved now, by calling
     * `$result->resolve(VALUE)` or `$result->reject(REASON)`
     * here, or make sure that one of them will be called in
     * the future.
     */

    return $result;
}

Supporting other promises yourself

To support other promise implementations yourself, the convention has been to use reflection to inspect the then() method.

Moebius Promise provides two ways to support other promises and ensure a consistent usage:

Casting

use Moebius\Promise;

function accepting_a_promise(object $thenable) {
    /**
     * @throws InvalidArgumentException if the object is not a promise
     */
    $promise = Moebius\Promise::cast($thenable);
}

Implementation details

In order to maintain compatability both Guzzle and PhpHttp promises, we have made some "trickery". It turns out that PhpHttp-promises are modelled after Guzzle promises, and are in fact compatible. Guzzle promises are a superset of PhpHttp promises, so if PhpHttp is installed - it will be class_alias()'ed to replace the GuzzleHttp\Promise\PromiseInterface.

These constants now live in the Moebius\Promise\SuperPromiseInterface class, so that they are available in both child classes while not being ambiguous according to PHP.

Promise resolution

Guzzle is quite particular when it comes to promise resolution, in that it will defer running the resolve function until you actually request the value. This is not ideal for an event loop implementation - because, for example if your task takes 1 second to run - you would want to start running that task as soon as possible. This is not noticeable when only using it with Guzzle, but when combined with other async tasks it becomes annoying.

We don't expect this to be a problem.

Promise::wait()

Guzzle and PhpHttp implements a wait() function, which is intended to start running the asynchronous jobs - almost like using the promise tree as an event-loop.

Basic usage

Normally you will pass a resolve function into the promise when it is constructed. This variant is the most common way to use promises.

use Moebius\Promise;

function some_function() {
    return new Promise(function($resolve, $reject) {
        // This function is immediately run when constructing the promise

        $resolve("Some value");         // or $reject(new Exception());
    });
}

Deferred usage

In some cases, you are unable to resolve the promise from inside the promise. This way you can hold on to a reference of the promise and resolve (or reject) it after you return it.

use Moebius\Promise;

$promise = new Promise();

// send the promise off to some function
some_function($promise);

// resolve it at any later time
$promise->resolve("Some value");    // or $promise->reject(new Exception())

Note: While is possible to call the resolve/reject methods multiple times, only the first call has an effect.

API documentation

Handling multiple promises efficiently:

  • Promise::all(iterable $promises): Promise. If all promises are resolved, the returned promise will resolve with an array of all the promises. If any of the promises are rejected, the returned promise is also rejected.

  • Promise::allSettled(iterable $promises): Promise. Once all the promise have a result, the returned promise is resolved with an array of the promises.

  • Promise::any(iterable $promises): Promise. If any of the promises are resolved, the returned promise is resolved with the first value. If all promises are rejected, the returned promise is rejected.

  • Promise::race(iterable $promises): Promise. The first promise which is either resolved or rejected will be the result of the returned promise.

Interoperability with other promise implementations:

  • Promise::cast($promise): Promise. Any object with a promise-like 'then' function is converted into a Moebius\Promise instance.

Subscribing to the result of a promise:

  • $promise->then(callable $onFulfilled=null, callable $onRejected=null): Promise. The passed functions will be invoked immediately if the promise has already been settled (fulfilled or rejected). The returned promise is a new promise which will be resolved or rejected with the value from the callbacks.

Resolving a promise externally:

  • $promise->resolve($value).

  • $promise->reject($reason).

moebius/promise 适用场景与选型建议

moebius/promise 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 910 次下载、GitHub Stars 达 0, 最近一次更新时间为 2022 年 04 月 04 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 moebius/promise 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 moebius/promise 我们能提供哪些服务?
定制开发 / 二次开发

基于 moebius/promise 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 910
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 3
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2022-04-04