Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
Promise
2
=======
3
 
4
A lightweight implementation of
5
[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP.
6
 
7
[![Build Status](https://travis-ci.org/reactphp/promise.svg?branch=master)](http://travis-ci.org/reactphp/promise)
8
[![Coverage Status](https://coveralls.io/repos/github/reactphp/promise/badge.svg?branch=master)](https://coveralls.io/github/reactphp/promise?branch=master)
9
 
10
Table of Contents
11
-----------------
12
 
13
1. [Introduction](#introduction)
14
2. [Concepts](#concepts)
15
   * [Deferred](#deferred)
16
   * [Promise](#promise-1)
17
3. [API](#api)
18
   * [Deferred](#deferred-1)
19
     * [Deferred::promise()](#deferredpromise)
20
     * [Deferred::resolve()](#deferredresolve)
21
     * [Deferred::reject()](#deferredreject)
22
     * [Deferred::notify()](#deferrednotify)
23
   * [PromiseInterface](#promiseinterface)
24
     * [PromiseInterface::then()](#promiseinterfacethen)
25
   * [ExtendedPromiseInterface](#extendedpromiseinterface)
26
        * [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone)
27
        * [ExtendedPromiseInterface::otherwise()](#extendedpromiseinterfaceotherwise)
28
        * [ExtendedPromiseInterface::always()](#extendedpromiseinterfacealways)
29
        * [ExtendedPromiseInterface::progress()](#extendedpromiseinterfaceprogress)
30
   * [CancellablePromiseInterface](#cancellablepromiseinterface)
31
        * [CancellablePromiseInterface::cancel()](#cancellablepromiseinterfacecancel)
32
   * [Promise](#promise-2)
33
   * [FulfilledPromise](#fulfilledpromise)
34
   * [RejectedPromise](#rejectedpromise)
35
   * [LazyPromise](#lazypromise)
36
   * [Functions](#functions)
37
     * [resolve()](#resolve)
38
     * [reject()](#reject)
39
     * [all()](#all)
40
     * [race()](#race)
41
     * [any()](#any)
42
     * [some()](#some)
43
     * [map()](#map)
44
     * [reduce()](#reduce)
45
   * [PromisorInterface](#promisorinterface)
46
4. [Examples](#examples)
47
   * [How to use Deferred](#how-to-use-deferred)
48
   * [How promise forwarding works](#how-promise-forwarding-works)
49
     * [Resolution forwarding](#resolution-forwarding)
50
     * [Rejection forwarding](#rejection-forwarding)
51
     * [Mixed resolution and rejection forwarding](#mixed-resolution-and-rejection-forwarding)
52
     * [Progress event forwarding](#progress-event-forwarding)
53
   * [done() vs. then()](#done-vs-then)
54
5. [Install](#install)
55
6. [Credits](#credits)
56
7. [License](#license)
57
 
58
Introduction
59
------------
60
 
61
Promise is a library implementing
62
[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP.
63
 
64
It also provides several other useful promise-related concepts, such as joining
65
multiple promises and mapping and reducing collections of promises.
66
 
67
If you've never heard about promises before,
68
[read this first](https://gist.github.com/3889970).
69
 
70
Concepts
71
--------
72
 
73
### Deferred
74
 
75
A **Deferred** represents a computation or unit of work that may not have
76
completed yet. Typically (but not always), that computation will be something
77
that executes asynchronously and completes at some point in the future.
78
 
79
### Promise
80
 
81
While a deferred represents the computation itself, a **Promise** represents
82
the result of that computation. Thus, each deferred has a promise that acts as
83
a placeholder for its actual result.
84
 
85
API
86
---
87
 
88
### Deferred
89
 
90
A deferred represents an operation whose resolution is pending. It has separate
91
promise and resolver parts.
92
 
93
```php
94
$deferred = new React\Promise\Deferred();
95
 
96
$promise = $deferred->promise();
97
 
98
$deferred->resolve(mixed $value = null);
99
$deferred->reject(mixed $reason = null);
100
$deferred->notify(mixed $update = null);
101
```
102
 
103
The `promise` method returns the promise of the deferred.
104
 
105
The `resolve` and `reject` methods control the state of the deferred.
106
 
107
The deprecated `notify` method is for progress notification.
108
 
109
The constructor of the `Deferred` accepts an optional `$canceller` argument.
110
See [Promise](#promise-2) for more information.
111
 
112
#### Deferred::promise()
113
 
114
```php
115
$promise = $deferred->promise();
116
```
117
 
118
Returns the promise of the deferred, which you can hand out to others while
119
keeping the authority to modify its state to yourself.
120
 
121
#### Deferred::resolve()
122
 
123
```php
124
$deferred->resolve(mixed $value = null);
125
```
126
 
127
Resolves the promise returned by `promise()`. All consumers are notified by
128
having `$onFulfilled` (which they registered via `$promise->then()`) called with
129
`$value`.
130
 
131
If `$value` itself is a promise, the promise will transition to the state of
132
this promise once it is resolved.
133
 
134
#### Deferred::reject()
135
 
136
```php
137
$deferred->reject(mixed $reason = null);
138
```
139
 
140
Rejects the promise returned by `promise()`, signalling that the deferred's
141
computation failed.
142
All consumers are notified by having `$onRejected` (which they registered via
143
`$promise->then()`) called with `$reason`.
144
 
145
If `$reason` itself is a promise, the promise will be rejected with the outcome
146
of this promise regardless whether it fulfills or rejects.
147
 
148
#### Deferred::notify()
149
 
150
> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore.
151
 
152
```php
153
$deferred->notify(mixed $update = null);
154
```
155
 
156
Triggers progress notifications, to indicate to consumers that the computation
157
is making progress toward its result.
158
 
159
All consumers are notified by having `$onProgress` (which they registered via
160
`$promise->then()`) called with `$update`.
161
 
162
### PromiseInterface
163
 
164
The promise interface provides the common interface for all promise
165
implementations.
166
 
167
A promise represents an eventual outcome, which is either fulfillment (success)
168
and an associated value, or rejection (failure) and an associated reason.
169
 
170
Once in the fulfilled or rejected state, a promise becomes immutable.
171
Neither its state nor its result (or error) can be modified.
172
 
173
#### Implementations
174
 
175
* [Promise](#promise-2)
176
* [FulfilledPromise](#fulfilledpromise) (deprecated)
177
* [RejectedPromise](#rejectedpromise) (deprecated)
178
* [LazyPromise](#lazypromise) (deprecated)
179
 
180
#### PromiseInterface::then()
181
 
182
```php
183
$transformedPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
184
```
185
 
186
Transforms a promise's value by applying a function to the promise's fulfillment
187
or rejection value. Returns a new promise for the transformed result.
188
 
189
The `then()` method registers new fulfilled, rejection and progress handlers
190
with a promise (all parameters are optional):
191
 
192
  * `$onFulfilled` will be invoked once the promise is fulfilled and passed
193
    the result as the first argument.
194
  * `$onRejected` will be invoked once the promise is rejected and passed the
195
    reason as the first argument.
196
  * `$onProgress` (deprecated) will be invoked whenever the producer of the promise
197
    triggers progress notifications and passed a single argument (whatever it
198
    wants) to indicate progress.
199
 
200
It returns a new promise that will fulfill with the return value of either
201
`$onFulfilled` or `$onRejected`, whichever is called, or will reject with
202
the thrown exception if either throws.
203
 
204
A promise makes the following guarantees about handlers registered in
205
the same call to `then()`:
206
 
207
  1. Only one of `$onFulfilled` or `$onRejected` will be called,
208
     never both.
209
  2. `$onFulfilled` and `$onRejected` will never be called more
210
     than once.
211
  3. `$onProgress` (deprecated) may be called multiple times.
212
 
213
#### See also
214
 
215
* [resolve()](#resolve) - Creating a resolved promise
216
* [reject()](#reject) - Creating a rejected promise
217
* [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone)
218
* [done() vs. then()](#done-vs-then)
219
 
220
### ExtendedPromiseInterface
221
 
222
The ExtendedPromiseInterface extends the PromiseInterface with useful shortcut
223
and utility methods which are not part of the Promises/A specification.
224
 
225
#### Implementations
226
 
227
* [Promise](#promise-1)
228
* [FulfilledPromise](#fulfilledpromise) (deprecated)
229
* [RejectedPromise](#rejectedpromise) (deprecated)
230
* [LazyPromise](#lazypromise) (deprecated)
231
 
232
#### ExtendedPromiseInterface::done()
233
 
234
```php
235
$promise->done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
236
```
237
 
238
Consumes the promise's ultimate value if the promise fulfills, or handles the
239
ultimate error.
240
 
241
It will cause a fatal error if either `$onFulfilled` or `$onRejected` throw or
242
return a rejected promise.
243
 
244
Since the purpose of `done()` is consumption rather than transformation,
245
`done()` always returns `null`.
246
 
247
#### See also
248
 
249
* [PromiseInterface::then()](#promiseinterfacethen)
250
* [done() vs. then()](#done-vs-then)
251
 
252
#### ExtendedPromiseInterface::otherwise()
253
 
254
```php
255
$promise->otherwise(callable $onRejected);
256
```
257
 
258
Registers a rejection handler for promise. It is a shortcut for:
259
 
260
```php
261
$promise->then(null, $onRejected);
262
```
263
 
264
Additionally, you can type hint the `$reason` argument of `$onRejected` to catch
265
only specific errors.
266
 
267
```php
268
$promise
269
    ->otherwise(function (\RuntimeException $reason) {
270
        // Only catch \RuntimeException instances
271
        // All other types of errors will propagate automatically
272
    })
273
    ->otherwise(function ($reason) {
274
        // Catch other errors
275
    )};
276
```
277
 
278
#### ExtendedPromiseInterface::always()
279
 
280
```php
281
$newPromise = $promise->always(callable $onFulfilledOrRejected);
282
```
283
 
284
Allows you to execute "cleanup" type tasks in a promise chain.
285
 
286
It arranges for `$onFulfilledOrRejected` to be called, with no arguments,
287
when the promise is either fulfilled or rejected.
288
 
289
* If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully,
290
  `$newPromise` will fulfill with the same value as `$promise`.
291
* If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a
292
  rejected promise, `$newPromise` will reject with the thrown exception or
293
  rejected promise's reason.
294
* If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully,
295
  `$newPromise` will reject with the same reason as `$promise`.
296
* If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a
297
  rejected promise, `$newPromise` will reject with the thrown exception or
298
  rejected promise's reason.
299
 
300
`always()` behaves similarly to the synchronous finally statement. When combined
301
with `otherwise()`, `always()` allows you to write code that is similar to the familiar
302
synchronous catch/finally pair.
303
 
304
Consider the following synchronous code:
305
 
306
```php
307
try {
308
  return doSomething();
309
} catch(\Exception $e) {
310
    return handleError($e);
311
} finally {
312
    cleanup();
313
}
314
```
315
 
316
Similar asynchronous code (with `doSomething()` that returns a promise) can be
317
written:
318
 
319
```php
320
return doSomething()
321
    ->otherwise('handleError')
322
    ->always('cleanup');
323
```
324
 
325
#### ExtendedPromiseInterface::progress()
326
 
327
> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore.
328
 
329
```php
330
$promise->progress(callable $onProgress);
331
```
332
 
333
Registers a handler for progress updates from promise. It is a shortcut for:
334
 
335
```php
336
$promise->then(null, null, $onProgress);
337
```
338
 
339
### CancellablePromiseInterface
340
 
341
A cancellable promise provides a mechanism for consumers to notify the creator
342
of the promise that they are not longer interested in the result of an
343
operation.
344
 
345
#### CancellablePromiseInterface::cancel()
346
 
347
``` php
348
$promise->cancel();
349
```
350
 
351
The `cancel()` method notifies the creator of the promise that there is no
352
further interest in the results of the operation.
353
 
354
Once a promise is settled (either fulfilled or rejected), calling `cancel()` on
355
a promise has no effect.
356
 
357
#### Implementations
358
 
359
* [Promise](#promise-1)
360
* [FulfilledPromise](#fulfilledpromise) (deprecated)
361
* [RejectedPromise](#rejectedpromise) (deprecated)
362
* [LazyPromise](#lazypromise) (deprecated)
363
 
364
### Promise
365
 
366
Creates a promise whose state is controlled by the functions passed to
367
`$resolver`.
368
 
369
```php
370
$resolver = function (callable $resolve, callable $reject, callable $notify) {
371
    // Do some work, possibly asynchronously, and then
372
    // resolve or reject. You can notify of progress events (deprecated)
373
    // along the way if you want/need.
374
 
375
    $resolve($awesomeResult);
376
    // or throw new Exception('Promise rejected');
377
    // or $resolve($anotherPromise);
378
    // or $reject($nastyError);
379
    // or $notify($progressNotification);
380
};
381
 
382
$canceller = function () {
383
    // Cancel/abort any running operations like network connections, streams etc.
384
 
385
    // Reject promise by throwing an exception
386
    throw new Exception('Promise cancelled');
387
};
388
 
389
$promise = new React\Promise\Promise($resolver, $canceller);
390
```
391
 
392
The promise constructor receives a resolver function and an optional canceller
393
function which both will be called with 3 arguments:
394
 
395
  * `$resolve($value)` - Primary function that seals the fate of the
396
    returned promise. Accepts either a non-promise value, or another promise.
397
    When called with a non-promise value, fulfills promise with that value.
398
    When called with another promise, e.g. `$resolve($otherPromise)`, promise's
399
    fate will be equivalent to that of `$otherPromise`.
400
  * `$reject($reason)` - Function that rejects the promise. It is recommended to
401
    just throw an exception instead of using `$reject()`.
402
  * `$notify($update)` - Deprecated function that issues progress events for the promise.
403
 
404
If the resolver or canceller throw an exception, the promise will be rejected
405
with that thrown exception as the rejection reason.
406
 
407
The resolver function will be called immediately, the canceller function only
408
once all consumers called the `cancel()` method of the promise.
409
 
410
### FulfilledPromise
411
 
412
> Deprecated in v2.8.0: External usage of `FulfilledPromise` is deprecated, use `resolve()` instead.
413
 
414
Creates a already fulfilled promise.
415
 
416
```php
417
$promise = React\Promise\FulfilledPromise($value);
418
```
419
 
420
Note, that `$value` **cannot** be a promise. It's recommended to use
421
[resolve()](#resolve) for creating resolved promises.
422
 
423
### RejectedPromise
424
 
425
> Deprecated in v2.8.0: External usage of `RejectedPromise` is deprecated, use `reject()` instead.
426
 
427
Creates a already rejected promise.
428
 
429
```php
430
$promise = React\Promise\RejectedPromise($reason);
431
```
432
 
433
Note, that `$reason` **cannot** be a promise. It's recommended to use
434
[reject()](#reject) for creating rejected promises.
435
 
436
### LazyPromise
437
 
438
> Deprecated in v2.8.0: LazyPromise is deprecated and should not be used anymore.
439
 
440
Creates a promise which will be lazily initialized by `$factory` once a consumer
441
calls the `then()` method.
442
 
443
```php
444
$factory = function () {
445
    $deferred = new React\Promise\Deferred();
446
 
447
    // Do some heavy stuff here and resolve the deferred once completed
448
 
449
    return $deferred->promise();
450
};
451
 
452
$promise = new React\Promise\LazyPromise($factory);
453
 
454
// $factory will only be executed once we call then()
455
$promise->then(function ($value) {
456
});
457
```
458
 
459
### Functions
460
 
461
Useful functions for creating, joining, mapping and reducing collections of
462
promises.
463
 
464
All functions working on promise collections (like `all()`, `race()`, `some()`
465
etc.) support cancellation. This means, if you call `cancel()` on the returned
466
promise, all promises in the collection are cancelled. If the collection itself
467
is a promise which resolves to an array, this promise is also cancelled.
468
 
469
#### resolve()
470
 
471
```php
472
$promise = React\Promise\resolve(mixed $promiseOrValue);
473
```
474
 
475
Creates a promise for the supplied `$promiseOrValue`.
476
 
477
If `$promiseOrValue` is a value, it will be the resolution value of the
478
returned promise.
479
 
480
If `$promiseOrValue` is a thenable (any object that provides a `then()` method),
481
a trusted promise that follows the state of the thenable is returned.
482
 
483
If `$promiseOrValue` is a promise, it will be returned as is.
484
 
485
Note: The promise returned is always a promise implementing
486
[ExtendedPromiseInterface](#extendedpromiseinterface). If you pass in a custom
487
promise which only implements [PromiseInterface](#promiseinterface), this
488
promise will be assimilated to a extended promise following `$promiseOrValue`.
489
 
490
#### reject()
491
 
492
```php
493
$promise = React\Promise\reject(mixed $promiseOrValue);
494
```
495
 
496
Creates a rejected promise for the supplied `$promiseOrValue`.
497
 
498
If `$promiseOrValue` is a value, it will be the rejection value of the
499
returned promise.
500
 
501
If `$promiseOrValue` is a promise, its completion value will be the rejected
502
value of the returned promise.
503
 
504
This can be useful in situations where you need to reject a promise without
505
throwing an exception. For example, it allows you to propagate a rejection with
506
the value of another promise.
507
 
508
#### all()
509
 
510
```php
511
$promise = React\Promise\all(array|React\Promise\PromiseInterface $promisesOrValues);
512
```
513
 
514
Returns a promise that will resolve only once all the items in
515
`$promisesOrValues` have resolved. The resolution value of the returned promise
516
will be an array containing the resolution values of each of the items in
517
`$promisesOrValues`.
518
 
519
#### race()
520
 
521
```php
522
$promise = React\Promise\race(array|React\Promise\PromiseInterface $promisesOrValues);
523
```
524
 
525
Initiates a competitive race that allows one winner. Returns a promise which is
526
resolved in the same way the first settled promise resolves.
527
 
528
#### any()
529
 
530
```php
531
$promise = React\Promise\any(array|React\Promise\PromiseInterface $promisesOrValues);
532
```
533
 
534
Returns a promise that will resolve when any one of the items in
535
`$promisesOrValues` resolves. The resolution value of the returned promise
536
will be the resolution value of the triggering item.
537
 
538
The returned promise will only reject if *all* items in `$promisesOrValues` are
539
rejected. The rejection value will be an array of all rejection reasons.
540
 
541
The returned promise will also reject with a `React\Promise\Exception\LengthException`
542
if `$promisesOrValues` contains 0 items.
543
 
544
#### some()
545
 
546
```php
547
$promise = React\Promise\some(array|React\Promise\PromiseInterface $promisesOrValues, integer $howMany);
548
```
549
 
550
Returns a promise that will resolve when `$howMany` of the supplied items in
551
`$promisesOrValues` resolve. The resolution value of the returned promise
552
will be an array of length `$howMany` containing the resolution values of the
553
triggering items.
554
 
555
The returned promise will reject if it becomes impossible for `$howMany` items
556
to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items
557
reject). The rejection value will be an array of
558
`(count($promisesOrValues) - $howMany) + 1` rejection reasons.
559
 
560
The returned promise will also reject with a `React\Promise\Exception\LengthException`
561
if `$promisesOrValues` contains less items than `$howMany`.
562
 
563
#### map()
564
 
565
```php
566
$promise = React\Promise\map(array|React\Promise\PromiseInterface $promisesOrValues, callable $mapFunc);
567
```
568
 
569
Traditional map function, similar to `array_map()`, but allows input to contain
570
promises and/or values, and `$mapFunc` may return either a value or a promise.
571
 
572
The map function receives each item as argument, where item is a fully resolved
573
value of a promise or value in `$promisesOrValues`.
574
 
575
#### reduce()
576
 
577
```php
578
$promise = React\Promise\reduce(array|React\Promise\PromiseInterface $promisesOrValues, callable $reduceFunc , $initialValue = null);
579
```
580
 
581
Traditional reduce function, similar to `array_reduce()`, but input may contain
582
promises and/or values, and `$reduceFunc` may return either a value or a
583
promise, *and* `$initialValue` may be a promise or a value for the starting
584
value.
585
 
586
### PromisorInterface
587
 
588
The `React\Promise\PromisorInterface` provides a common interface for objects
589
that provide a promise. `React\Promise\Deferred` implements it, but since it
590
is part of the public API anyone can implement it.
591
 
592
Examples
593
--------
594
 
595
### How to use Deferred
596
 
597
```php
598
function getAwesomeResultPromise()
599
{
600
    $deferred = new React\Promise\Deferred();
601
 
602
    // Execute a Node.js-style function using the callback pattern
603
    computeAwesomeResultAsynchronously(function ($error, $result) use ($deferred) {
604
        if ($error) {
605
            $deferred->reject($error);
606
        } else {
607
            $deferred->resolve($result);
608
        }
609
    });
610
 
611
    // Return the promise
612
    return $deferred->promise();
613
}
614
 
615
getAwesomeResultPromise()
616
    ->then(
617
        function ($value) {
618
            // Deferred resolved, do something with $value
619
        },
620
        function ($reason) {
621
            // Deferred rejected, do something with $reason
622
        },
623
        function ($update) {
624
            // Progress notification triggered, do something with $update
625
        }
626
    );
627
```
628
 
629
### How promise forwarding works
630
 
631
A few simple examples to show how the mechanics of Promises/A forwarding works.
632
These examples are contrived, of course, and in real usage, promise chains will
633
typically be spread across several function calls, or even several levels of
634
your application architecture.
635
 
636
#### Resolution forwarding
637
 
638
Resolved promises forward resolution values to the next promise.
639
The first promise, `$deferred->promise()`, will resolve with the value passed
640
to `$deferred->resolve()` below.
641
 
642
Each call to `then()` returns a new promise that will resolve with the return
643
value of the previous handler. This creates a promise "pipeline".
644
 
645
```php
646
$deferred = new React\Promise\Deferred();
647
 
648
$deferred->promise()
649
    ->then(function ($x) {
650
        // $x will be the value passed to $deferred->resolve() below
651
        // and returns a *new promise* for $x + 1
652
        return $x + 1;
653
    })
654
    ->then(function ($x) {
655
        // $x === 2
656
        // This handler receives the return value of the
657
        // previous handler.
658
        return $x + 1;
659
    })
660
    ->then(function ($x) {
661
        // $x === 3
662
        // This handler receives the return value of the
663
        // previous handler.
664
        return $x + 1;
665
    })
666
    ->then(function ($x) {
667
        // $x === 4
668
        // This handler receives the return value of the
669
        // previous handler.
670
        echo 'Resolve ' . $x;
671
    });
672
 
673
$deferred->resolve(1); // Prints "Resolve 4"
674
```
675
 
676
#### Rejection forwarding
677
 
678
Rejected promises behave similarly, and also work similarly to try/catch:
679
When you catch an exception, you must rethrow for it to propagate.
680
 
681
Similarly, when you handle a rejected promise, to propagate the rejection,
682
"rethrow" it by either returning a rejected promise, or actually throwing
683
(since promise translates thrown exceptions into rejections)
684
 
685
```php
686
$deferred = new React\Promise\Deferred();
687
 
688
$deferred->promise()
689
    ->then(function ($x) {
690
        throw new \Exception($x + 1);
691
    })
692
    ->otherwise(function (\Exception $x) {
693
        // Propagate the rejection
694
        throw $x;
695
    })
696
    ->otherwise(function (\Exception $x) {
697
        // Can also propagate by returning another rejection
698
        return React\Promise\reject(
699
            new \Exception($x->getMessage() + 1)
700
        );
701
    })
702
    ->otherwise(function ($x) {
703
        echo 'Reject ' . $x->getMessage(); // 3
704
    });
705
 
706
$deferred->resolve(1);  // Prints "Reject 3"
707
```
708
 
709
#### Mixed resolution and rejection forwarding
710
 
711
Just like try/catch, you can choose to propagate or not. Mixing resolutions and
712
rejections will still forward handler results in a predictable way.
713
 
714
```php
715
$deferred = new React\Promise\Deferred();
716
 
717
$deferred->promise()
718
    ->then(function ($x) {
719
        return $x + 1;
720
    })
721
    ->then(function ($x) {
722
        throw new \Exception($x + 1);
723
    })
724
    ->otherwise(function (\Exception $x) {
725
        // Handle the rejection, and don't propagate.
726
        // This is like catch without a rethrow
727
        return $x->getMessage() + 1;
728
    })
729
    ->then(function ($x) {
730
        echo 'Mixed ' . $x; // 4
731
    });
732
 
733
$deferred->resolve(1);  // Prints "Mixed 4"
734
```
735
 
736
#### Progress event forwarding
737
 
738
> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore.
739
 
740
In the same way as resolution and rejection handlers, your progress handler
741
**MUST** return a progress event to be propagated to the next link in the chain.
742
If you return nothing, `null` will be propagated.
743
 
744
Also in the same way as resolutions and rejections, if you don't register a
745
progress handler, the update will be propagated through.
746
 
747
If your progress handler throws an exception, the exception will be propagated
748
to the next link in the chain. The best thing to do is to ensure your progress
749
handlers do not throw exceptions.
750
 
751
This gives you the opportunity to transform progress events at each step in the
752
chain so that they are meaningful to the next step. It also allows you to choose
753
not to transform them, and simply let them propagate untransformed, by not
754
registering a progress handler.
755
 
756
```php
757
$deferred = new React\Promise\Deferred();
758
 
759
$deferred->promise()
760
    ->progress(function ($update) {
761
        return $update + 1;
762
    })
763
    ->progress(function ($update) {
764
        echo 'Progress ' . $update; // 2
765
    });
766
 
767
$deferred->notify(1);  // Prints "Progress 2"
768
```
769
 
770
### done() vs. then()
771
 
772
The golden rule is:
773
 
774
    Either return your promise, or call done() on it.
775
 
776
At a first glance, `then()` and `done()` seem very similar. However, there are
777
important distinctions.
778
 
779
The intent of `then()` is to transform a promise's value and to pass or return
780
a new promise for the transformed value along to other parts of your code.
781
 
782
The intent of `done()` is to consume a promise's value, transferring
783
responsibility for the value to your code.
784
 
785
In addition to transforming a value, `then()` allows you to recover from, or
786
propagate intermediate errors. Any errors that are not handled will be caught
787
by the promise machinery and used to reject the promise returned by `then()`.
788
 
789
Calling `done()` transfers all responsibility for errors to your code. If an
790
error (either a thrown exception or returned rejection) escapes the
791
`$onFulfilled` or `$onRejected` callbacks you provide to done, it will be
792
rethrown in an uncatchable way causing a fatal error.
793
 
794
```php
795
function getJsonResult()
796
{
797
    return queryApi()
798
        ->then(
799
            // Transform API results to an object
800
            function ($jsonResultString) {
801
                return json_decode($jsonResultString);
802
            },
803
            // Transform API errors to an exception
804
            function ($jsonErrorString) {
805
                $object = json_decode($jsonErrorString);
806
                throw new ApiErrorException($object->errorMessage);
807
            }
808
        );
809
}
810
 
811
// Here we provide no rejection handler. If the promise returned has been
812
// rejected, the ApiErrorException will be thrown
813
getJsonResult()
814
    ->done(
815
        // Consume transformed object
816
        function ($jsonResultObject) {
817
            // Do something with $jsonResultObject
818
        }
819
    );
820
 
821
// Here we provide a rejection handler which will either throw while debugging
822
// or log the exception
823
getJsonResult()
824
    ->done(
825
        function ($jsonResultObject) {
826
            // Do something with $jsonResultObject
827
        },
828
        function (ApiErrorException $exception) {
829
            if (isDebug()) {
830
                throw $exception;
831
            } else {
832
                logException($exception);
833
            }
834
        }
835
    );
836
```
837
 
838
Note that if a rejection value is not an instance of `\Exception`, it will be
839
wrapped in an exception of the type `React\Promise\UnhandledRejectionException`.
840
 
841
You can get the original rejection reason by calling `$exception->getReason()`.
842
 
843
Install
844
-------
845
 
846
The recommended way to install this library is [through Composer](https://getcomposer.org).
847
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
848
 
849
This project follows [SemVer](https://semver.org/).
850
This will install the latest supported version:
851
 
852
```bash
853
$ composer require react/promise:^2.8
854
```
855
 
856
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
857
 
858
This project aims to run on any platform and thus does not require any PHP
859
extensions and supports running on legacy PHP 5.4 through current PHP 7+ and HHVM.
860
It's *highly recommended to use PHP 7+* for this project due to its vast
861
performance improvements.
862
 
863
Credits
864
-------
865
 
866
Promise is a port of [when.js](https://github.com/cujojs/when)
867
by [Brian Cavalier](https://github.com/briancavalier).
868
 
869
Also, large parts of the documentation have been ported from the when.js
870
[Wiki](https://github.com/cujojs/when/wiki) and the
871
[API docs](https://github.com/cujojs/when/blob/master/docs/api.md).
872
 
873
License
874
-------
875
 
876
Released under the [MIT](LICENSE) license.