Implementasi ringan CommonJS Promises/A untuk PHP.
Promise adalah perpustakaan yang mengimplementasikan CommonJS Promises/A untuk PHP.
Hal ini juga memberikan beberapa konsep terkait janji berguna lainnya, seperti menggabungkan beberapa janji dan memetakan serta mengurangi kumpulan janji.
Jika Anda belum pernah mendengar tentang janji sebelumnya, bacalah ini terlebih dahulu.
Yang Ditangguhkan mewakili perhitungan atau unit pekerjaan yang mungkin belum selesai. Biasanya (tetapi tidak selalu), komputasi tersebut akan menjadi sesuatu yang dijalankan secara asinkron dan selesai pada suatu saat di masa mendatang.
Meskipun penundaan mewakili penghitungan itu sendiri, Janji mewakili hasil penghitungan tersebut. Jadi, masing-masing penangguhan memiliki janji yang bertindak sebagai pengganti hasil aktualnya.
Yang ditangguhkan mewakili operasi yang resolusinya tertunda. Ini memiliki bagian janji dan penyelesai yang terpisah.
$ deferred = new React Promise Deferred ();
$ promise = $ deferred -> promise ();
$ deferred -> resolve (mixed $ value );
$ deferred -> reject (Throwable $ reason );
Metode promise
mengembalikan janji yang ditangguhkan.
Metode resolve
dan reject
mengontrol keadaan yang ditangguhkan.
Konstruktor Deferred
menerima argumen opsional $canceller
. Lihat Janji untuk informasi lebih lanjut.
$ promise = $ deferred -> promise ();
Mengembalikan janji yang ditangguhkan, yang dapat Anda berikan kepada orang lain sambil tetap memiliki wewenang untuk mengubah statusnya kepada Anda sendiri.
$ deferred -> resolve (mixed $ value );
Menyelesaikan janji yang dikembalikan oleh promise()
. Semua konsumen diberi tahu dengan memanggil $onFulfilled
(yang mereka daftarkan melalui $promise->then()
) dengan $value
.
Jika $value
itu sendiri adalah sebuah janji, janji tersebut akan bertransisi ke keadaan janji ini setelah janji tersebut diselesaikan.
Lihat juga fungsi resolve()
.
$ deferred -> reject (Throwable $ reason );
Menolak janji yang dikembalikan oleh promise()
, menandakan bahwa perhitungan yang ditangguhkan gagal. Semua konsumen diberitahu dengan memanggil $onRejected
(yang mereka daftarkan melalui $promise->then()
) dengan $reason
.
Lihat juga fungsi reject()
.
Antarmuka janji menyediakan antarmuka umum untuk semua implementasi janji. Lihat Promise untuk satu-satunya implementasi publik yang dipaparkan dalam paket ini.
Janji mewakili hasil akhir, yang berupa pemenuhan (kesuksesan) dan nilai terkait, atau penolakan (kegagalan) dan alasan terkait.
Setelah dalam keadaan dipenuhi atau ditolak, sebuah janji menjadi tidak dapat diubah. Baik status maupun hasil (atau kesalahannya) tidak dapat diubah.
$ transformedPromise = $ promise -> then (callable $ onFulfilled = null , callable $ onRejected = null );
Mengubah nilai janji dengan menerapkan fungsi pada nilai pemenuhan atau penolakan janji. Mengembalikan janji baru untuk hasil yang diubah.
Metode then()
mendaftarkan penangan baru yang terpenuhi dan ditolak dengan sebuah janji (semua parameter bersifat opsional):
$onFulfilled
akan dipanggil setelah janji dipenuhi dan memberikan hasilnya sebagai argumen pertama.$onRejected
akan dipanggil setelah janji ditolak dan alasannya diberikan sebagai argumen pertama. Ini mengembalikan janji baru yang akan dipenuhi dengan nilai kembalian $onFulfilled
atau $onRejected
, mana pun yang dipanggil, atau akan ditolak dengan pengecualian yang dilempar jika salah satu dilempar.
Sebuah janji memberikan jaminan berikut tentang penangan yang terdaftar dalam panggilan yang sama ke then()
:
$onFulfilled
atau $onRejected
yang akan dipanggil, tidak pernah keduanya.$onFulfilled
dan $onRejected
tidak akan pernah dipanggil lebih dari sekali. $ promise -> catch (callable $ onRejected );
Mendaftarkan penangan penolakan untuk janji. Ini adalah jalan pintas untuk:
$ promise -> then ( null , $ onRejected );
Selain itu, Anda dapat mengetikkan petunjuk argumen $reason
dari $onRejected
untuk menangkap kesalahan tertentu saja.
$ promise
-> catch ( function ( RuntimeException $ reason ) {
// Only catch RuntimeException instances
// All other types of errors will propagate automatically
})
-> catch ( function ( Throwable $ reason ) {
// Catch other errors
});
$ newPromise = $ promise -> finally (callable $ onFulfilledOrRejected );
Memungkinkan Anda menjalankan tugas jenis "pembersihan" dalam rantai janji.
Ini mengatur agar $onFulfilledOrRejected
dipanggil, tanpa argumen, ketika janji dipenuhi atau ditolak.
$promise
terpenuhi, dan $onFulfilledOrRejected
berhasil dikembalikan, $newPromise
akan terpenuhi dengan nilai yang sama dengan $promise
.$promise
terpenuhi, dan $onFulfilledOrRejected
melemparkan atau mengembalikan janji yang ditolak, $newPromise
akan menolak dengan pengecualian yang diberikan atau alasan janji yang ditolak.$promise
ditolak, dan $onFulfilledOrRejected
berhasil dikembalikan, $newPromise
akan menolak dengan alasan yang sama seperti $promise
.$promise
menolak, dan $onFulfilledOrRejected
melemparkan atau mengembalikan janji yang ditolak, $newPromise
akan menolak dengan pengecualian yang diberikan atau alasan janji ditolak. finally()
berperilaku mirip dengan pernyataan sinkron akhirnya. Ketika dikombinasikan dengan catch()
, finally()
memungkinkan Anda menulis kode yang mirip dengan pasangan catch/finally sinkron yang sudah dikenal.
Pertimbangkan kode sinkron berikut:
try {
return doSomething ();
} catch ( Throwable $ e ) {
return handleError ( $ e );
} finally {
cleanup ();
}
Kode asinkron serupa (dengan doSomething()
yang mengembalikan janji) dapat ditulis:
return doSomething ()
-> catch ( ' handleError ' )
-> finally ( ' cleanup ' );
$ promise -> cancel ();
Metode cancel()
memberi tahu pembuat janji bahwa tidak ada lagi kepentingan dalam hasil operasi.
Setelah janji dilunasi (baik dipenuhi atau ditolak), pemanggilan cancel()
pada janji tidak akan berpengaruh.
Tidak digunakan lagi sejak v3.0.0, lihat
catch()
saja.
Metode otherwise()
mendaftarkan penangan penolakan untuk sebuah janji.
Metode ini tetap ada hanya karena alasan BC dan untuk memudahkan peningkatan antar versi. Ini adalah alias untuk:
$ promise -> catch ( $ onRejected );
Tidak digunakan lagi sejak v3.0.0, lihat
finally()
sebagai gantinya.
Metode always()
memungkinkan Anda menjalankan tugas jenis "pembersihan" dalam rantai janji.
Metode ini tetap ada hanya karena alasan BC dan untuk memudahkan peningkatan antar versi. Ini adalah alias untuk:
$ promise -> finally ( $ onFulfilledOrRejected );
Membuat janji yang statusnya dikontrol oleh fungsi yang diteruskan ke $resolver
.
$ resolver = function ( callable $ resolve , callable $ reject ) {
// Do some work, possibly asynchronously, and then
// resolve or reject.
$ resolve ( $ awesomeResult );
// or throw new Exception('Promise rejected');
// or $resolve($anotherPromise);
// or $reject($nastyError);
};
$ canceller = function () {
// Cancel/abort any running operations like network connections, streams etc.
// Reject promise by throwing an exception
throw new Exception ( ' Promise cancelled ' );
};
$ promise = new React Promise Promise ( $ resolver , $ canceller );
Konstruktor janji menerima fungsi penyelesai dan fungsi pembatalan opsional yang keduanya akan dipanggil dengan dua argumen:
$resolve($value)
- Fungsi utama yang menentukan nasib janji yang dikembalikan. Menerima nilai non-janji, atau janji lainnya. Ketika dipanggil dengan nilai non-janji, penuhi janji dengan nilai tersebut. Ketika dipanggil dengan janji lain, misalnya $resolve($otherPromise)
, nasib janji akan setara dengan $otherPromise
.$reject($reason)
- Fungsi yang menolak janji. Disarankan untuk hanya memberikan pengecualian daripada menggunakan $reject()
.Jika penyelesai atau pembatalan memberikan pengecualian, janji akan ditolak dengan pengecualian yang diberikan sebagai alasan penolakan.
Fungsi penyelesai akan dipanggil segera, fungsi pembatalan hanya sekali semua konsumen memanggil metode cancel()
yang dijanjikan.
Fungsi yang berguna untuk membuat dan menggabungkan kumpulan janji.
Semua fungsi yang bekerja pada kumpulan janji (seperti all()
, race()
, dll.) mendukung pembatalan. Artinya, jika Anda memanggil cancel()
pada janji yang dikembalikan, semua janji dalam koleksi akan dibatalkan.
$ promise = React Promise resolve (mixed $ promiseOrValue );
Membuat janji untuk $promiseOrValue
yang disediakan.
Jika $promiseOrValue
adalah sebuah nilai, maka itu akan menjadi nilai resolusi dari janji yang dikembalikan.
Jika $promiseOrValue
adalah yang dapat digunakan (objek apa pun yang menyediakan metode then()
), janji tepercaya yang mengikuti keadaan yang dapat dikembalikan akan dikembalikan.
Jika $promiseOrValue
adalah sebuah janji, maka janji tersebut akan dikembalikan apa adanya.
$promise
yang dihasilkan mengimplementasikan PromiseInterface
dan dapat digunakan seperti janji lainnya:
$ promise = React Promise resolve ( 42 );
$ promise -> then ( function ( int $ result ): void {
var_dump ( $ result );
}, function ( Throwable $ e ): void {
echo ' Error: ' . $ e -> getMessage () . PHP_EOL ;
});
$ promise = React Promise reject (Throwable $ reason );
Membuat janji yang ditolak untuk $reason
yang diberikan.
Perhatikan bahwa antarmuka Throwable
yang diperkenalkan di PHP 7 mencakup kesalahan internal PHP pengguna lahan Exception
dan Error
. Dengan menerapkan Throwable
sebagai alasan untuk menolak janji, kesalahan bahasa apa pun atau pengecualian wilayah pengguna dapat digunakan untuk menolak janji.
$promise
yang dihasilkan mengimplementasikan PromiseInterface
dan dapat digunakan seperti janji lainnya:
$ promise = React Promise reject ( new RuntimeException ( ' Request failed ' ));
$ promise -> then ( function ( int $ result ): void {
var_dump ( $ result );
}, function ( Throwable $ e ): void {
echo ' Error: ' . $ e -> getMessage () . PHP_EOL ;
});
Perhatikan bahwa janji yang ditolak harus selalu ditangani serupa dengan bagaimana setiap pengecualian harus selalu ditangkap dalam blok try
+ catch
. Jika Anda menghapus referensi terakhir ke janji yang ditolak dan belum ditangani, maka janji tersebut akan melaporkan penolakan janji yang tidak ditangani:
function incorrect (): int
{
$ promise = React Promise reject ( new RuntimeException ( ' Request failed ' ));
// Commented out: No rejection handler registered here.
// $promise->then(null, function (Throwable $e): void { /* ignore */ });
// Returning from a function will remove all local variable references, hence why
// this will report an unhandled promise rejection here.
return 42 ;
}
// Calling this function will log an error message plus its stack trace:
// Unhandled promise rejection with RuntimeException: Request failed in example.php:10
incorrect ();
Janji yang ditolak akan dianggap "ditangani" jika Anda mengetahui alasan penolakannya dengan metode then()
, metode catch()
, atau metode finally()
. Perhatikan bahwa masing-masing metode ini mengembalikan janji baru yang mungkin ditolak lagi jika Anda mengembalikan pengecualian.
Janji yang ditolak juga akan dianggap "ditangani" jika Anda membatalkan operasi dengan metode cancel()
(yang biasanya akan menolak janji jika masih tertunda).
Lihat juga fungsi set_rejection_handler()
.
$ promise = React Promise all (iterable $ promisesOrValues );
Mengembalikan janji yang akan terselesaikan hanya setelah semua item di $promisesOrValues
telah terselesaikan. Nilai resolusi dari janji yang dikembalikan akan berupa larik yang berisi nilai resolusi setiap item di $promisesOrValues
.
$ promise = React Promise race (iterable $ promisesOrValues );
Memulai perlombaan kompetitif yang memungkinkan satu pemenang. Mengembalikan janji yang diselesaikan dengan cara yang sama dengan penyelesaian janji pertama yang diselesaikan.
Janji yang dikembalikan akan tertunda tanpa batas waktu jika $promisesOrValues
berisi 0 item.
$ promise = React Promise any (iterable $ promisesOrValues );
Mengembalikan janji yang akan terselesaikan ketika salah satu item di $promisesOrValues
terselesaikan. Nilai resolusi dari janji yang dikembalikan akan menjadi nilai resolusi dari item pemicu.
Janji yang dikembalikan hanya akan ditolak jika semua item di $promisesOrValues
ditolak. Nilai penolakannya adalah ReactPromiseExceptionCompositeException
yang menampung semua alasan penolakan. Alasan penolakan dapat diperoleh dengan CompositeException::getThrowables()
.
Janji yang dikembalikan juga akan ditolak dengan ReactPromiseExceptionLengthException
jika $promisesOrValues
berisi 0 item.
React Promise set_rejection_handler(?callable $ callback ): ?callable;
Menetapkan pengendali penolakan global untuk penolakan janji yang tidak tertangani.
Perhatikan bahwa janji yang ditolak harus selalu ditangani serupa dengan bagaimana setiap pengecualian harus selalu ditangkap dalam blok try
+ catch
. Jika Anda menghapus referensi terakhir ke janji yang ditolak dan belum ditangani, maka janji tersebut akan melaporkan penolakan janji yang tidak ditangani. Lihat juga fungsi reject()
untuk lebih jelasnya.
Argumen ?callable $callback
HARUS berupa fungsi panggilan balik yang valid yang menerima satu argumen Throwable
atau nilai null
untuk memulihkan penangan penolakan janji default. Nilai kembalian fungsi panggilan balik akan diabaikan dan tidak berpengaruh, jadi Anda HARUS mengembalikan nilai void
. Fungsi panggilan balik TIDAK HARUS dilempar atau program akan dihentikan dengan kesalahan fatal.
Fungsi ini mengembalikan penangan penolakan sebelumnya atau null
jika menggunakan penangan penolakan janji default.
Penangan penolakan janji default akan mencatat pesan kesalahan ditambah jejak tumpukannya:
// Unhandled promise rejection with RuntimeException: Unhandled in example.php:2
React Promise reject ( new RuntimeException ( ' Unhandled ' ));
Penangan penolakan janji dapat digunakan untuk menyesuaikan pesan log atau menulis ke target log khusus. Sebagai aturan praktis, fungsi ini hanya boleh digunakan sebagai pilihan terakhir dan penolakan janji paling baik ditangani dengan metode then()
, metode catch()
, atau metode finally()
. Lihat juga fungsi reject()
untuk lebih jelasnya.
function getAwesomeResultPromise ()
{
$ deferred = new React Promise Deferred ();
// Execute a Node.js-style function using the callback pattern
computeAwesomeResultAsynchronously ( function ( Throwable $ error , $ result ) use ( $ deferred ) {
if ( $ error ) {
$ deferred -> reject ( $ error );
} else {
$ deferred -> resolve ( $ result );
}
});
// Return the promise
return $ deferred -> promise ();
}
getAwesomeResultPromise ()
-> then (
function ( $ value ) {
// Deferred resolved, do something with $value
},
function ( Throwable $ reason ) {
// Deferred rejected, do something with $reason
}
);
Beberapa contoh sederhana untuk menunjukkan cara kerja penerusan Promises/A. Tentu saja, contoh-contoh ini dibuat-buat, dan dalam penggunaan nyata, rantai janji biasanya tersebar di beberapa pemanggilan fungsi, atau bahkan beberapa tingkat arsitektur aplikasi Anda.
Janji yang terselesaikan meneruskan nilai resolusi ke janji berikutnya. Janji pertama, $deferred->promise()
, akan diselesaikan dengan nilai yang diteruskan ke $deferred->resolve()
di bawah.
Setiap panggilan ke then()
mengembalikan janji baru yang akan diselesaikan dengan nilai kembalian dari pengendali sebelumnya. Hal ini menciptakan janji "saluran pipa".
$ deferred = new React Promise Deferred ();
$ deferred -> promise ()
-> then ( function ( $ x ) {
// $x will be the value passed to $deferred->resolve() below
// and returns a *new promise* for $x + 1
return $ x + 1 ;
})
-> then ( function ( $ x ) {
// $x === 2
// This handler receives the return value of the
// previous handler.
return $ x + 1 ;
})
-> then ( function ( $ x ) {
// $x === 3
// This handler receives the return value of the
// previous handler.
return $ x + 1 ;
})
-> then ( function ( $ x ) {
// $x === 4
// This handler receives the return value of the
// previous handler.
echo ' Resolve ' . $ x ;
});
$ deferred -> resolve ( 1 ); // Prints "Resolve 4"
Janji yang ditolak berperilaku serupa, dan cara kerjanya juga sama untuk mencoba/menangkap: Saat Anda menangkap pengecualian, Anda harus melemparkannya kembali agar dapat disebarkan.
Demikian pula, ketika Anda menangani janji yang ditolak, untuk menyebarkan penolakan, "lemparkan kembali" janji tersebut dengan mengembalikan janji yang ditolak, atau benar-benar membuangnya (karena janji menerjemahkan pengecualian yang diberikan menjadi penolakan)
$ deferred = new React Promise Deferred ();
$ deferred -> promise ()
-> then ( function ( $ x ) {
throw new Exception ( $ x + 1 );
})
-> catch ( function ( Exception $ x ) {
// Propagate the rejection
throw $ x ;
})
-> catch ( function ( Exception $ x ) {
// Can also propagate by returning another rejection
return React Promise reject (
new Exception ( $ x -> getMessage () + 1 )
);
})
-> catch ( function ( $ x ) {
echo ' Reject ' . $ x -> getMessage (); // 3
});
$ deferred -> resolve ( 1 ); // Prints "Reject 3"
Sama seperti try/catch, Anda dapat memilih untuk menyebarkan atau tidak. Menggabungkan resolusi dan penolakan akan tetap meneruskan hasil penanganan dengan cara yang dapat diprediksi.
$ deferred = new React Promise Deferred ();
$ deferred -> promise ()
-> then ( function ( $ x ) {
return $ x + 1 ;
})
-> then ( function ( $ x ) {
throw new Exception ( $ x + 1 );
})
-> catch ( function ( Exception $ x ) {
// Handle the rejection, and don't propagate.
// This is like catch without a rethrow
return $ x -> getMessage () + 1 ;
})
-> then ( function ( $ x ) {
echo ' Mixed ' . $ x ; // 4
});
$ deferred -> resolve ( 1 ); // Prints "Mixed 4"
Cara yang disarankan untuk menginstal perpustakaan ini adalah melalui Komposer. Baru mengenal Komposer?
Proyek ini mengikuti SemVer. Ini akan menginstal versi terbaru yang didukung dari cabang ini:
composer require react/promise:^3.2
Lihat juga CHANGELOG untuk detail tentang peningkatan versi.
Proyek ini bertujuan untuk berjalan pada platform apa pun sehingga tidak memerlukan ekstensi PHP apa pun dan mendukung berjalan pada PHP 7.1 hingga PHP 8+ saat ini. Sangat disarankan untuk menggunakan versi PHP terbaru yang didukung untuk proyek ini.
Kami berkomitmen untuk menyediakan opsi dukungan jangka panjang (LTS) dan menyediakan jalur peningkatan yang lancar. Jika Anda menggunakan versi PHP yang lebih lama, Anda dapat menggunakan cabang 2.x
(PHP 5.4+) atau cabang 1.x
(PHP 5.3+) yang keduanya menyediakan API yang kompatibel namun tidak memanfaatkan fitur bahasa yang lebih baru. Anda dapat menargetkan beberapa versi sekaligus untuk mendukung versi PHP yang lebih luas seperti ini:
composer require " react/promise:^3 || ^2 || ^1 "
Untuk menjalankan test suite, Anda harus mengkloning repo ini terlebih dahulu, lalu menginstal semua dependensi melalui Composer:
composer install
Untuk menjalankan rangkaian pengujian, buka root proyek dan jalankan:
vendor/bin/phpunit
Selain itu, kami menggunakan PHPStan pada level maksimal untuk memastikan keamanan tipe di seluruh proyek:
vendor/bin/phpstan
Promise adalah port ketika.js oleh Brian Cavalier.
Selain itu, sebagian besar dokumentasi telah dipindahkan dari Wikiwhen.js dan dokumen API.
Dirilis di bawah lisensi MIT.