Uma implementação leve de CommonJS Promises/A para PHP.
Promise é uma biblioteca que implementa CommonJS Promises/A para PHP.
Ele também fornece vários outros conceitos úteis relacionados a promessas, como juntar múltiplas promessas e mapear e reduzir coleções de promessas.
Se você nunca ouviu falar sobre promessas antes, leia isto primeiro.
Um Adiado representa um cálculo ou unidade de trabalho que pode ainda não ter sido concluído. Normalmente (mas nem sempre), esse cálculo será algo executado de forma assíncrona e concluído em algum momento no futuro.
Enquanto um adiado representa o cálculo em si, uma promessa representa o resultado desse cálculo. Assim, cada adiamento possui uma promessa que atua como espaço reservado para seu resultado real.
Um diferido representa uma operação cuja resolução está pendente. Possui partes separadas de promessa e resolução.
$ deferred = new React Promise Deferred ();
$ promise = $ deferred -> promise ();
$ deferred -> resolve (mixed $ value );
$ deferred -> reject (Throwable $ reason );
O método promise
retorna a promessa do adiado.
Os métodos resolve
e reject
controlam o estado do adiado.
O construtor do Deferred
aceita um argumento opcional $canceller
. Consulte Promessa para obter mais informações.
$ promise = $ deferred -> promise ();
Retorna a promessa do adiado, que você pode distribuir a outros enquanto mantém a autoridade para modificar seu estado para si mesmo.
$ deferred -> resolve (mixed $ value );
Resolve a promessa retornada por promise()
. Todos os consumidores são notificados tendo $onFulfilled
(que eles registraram via $promise->then()
) chamado com $value
.
Se $value
em si for uma promessa, a promessa fará a transição para o estado desta promessa assim que for resolvida.
Veja também a função resolve()
.
$ deferred -> reject (Throwable $ reason );
Rejeita a promessa retornada por promise()
, sinalizando que o cálculo do adiado falhou. Todos os consumidores são notificados tendo $onRejected
(que eles registraram via $promise->then()
) chamado com $reason
.
Veja também a função reject()
.
A interface de promessa fornece a interface comum para todas as implementações de promessa. Consulte Promise para a única implementação pública exposta por este pacote.
Uma promessa representa um resultado final, que é o cumprimento (sucesso) e um valor associado, ou a rejeição (fracasso) e um motivo associado.
Uma vez no estado cumprido ou rejeitado, uma promessa torna-se imutável. Nem o seu estado nem o seu resultado (ou erro) podem ser modificados.
$ transformedPromise = $ promise -> then (callable $ onFulfilled = null , callable $ onRejected = null );
Transforma o valor de uma promessa aplicando uma função ao valor de cumprimento ou rejeição da promessa. Retorna uma nova promessa para o resultado transformado.
O método then()
registra novos manipuladores cumpridos e rejeitados com uma promessa (todos os parâmetros são opcionais):
$onFulfilled
será invocado assim que a promessa for cumprida e o resultado for passado como primeiro argumento.$onRejected
será invocado quando a promessa for rejeitada e o motivo for passado como primeiro argumento. Ele retorna uma nova promessa que será cumprida com o valor de retorno de $onFulfilled
ou $onRejected
, o que for chamado, ou será rejeitada com a exceção lançada se alguma delas for lançada.
Uma promessa oferece as seguintes garantias sobre manipuladores registrados na mesma chamada para then()
:
$onFulfilled
ou $onRejected
será chamado, nunca ambos.$onFulfilled
e $onRejected
nunca serão chamados mais de uma vez. $ promise -> catch (callable $ onRejected );
Registra um manipulador de rejeição para promessa. É um atalho para:
$ promise -> then ( null , $ onRejected );
Além disso, você pode digitar o argumento $reason
de $onRejected
para capturar apenas erros específicos.
$ 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 );
Permite executar tarefas do tipo "limpeza" em uma cadeia de promessas.
Ele faz com que $onFulfilledOrRejected
seja chamado, sem argumentos, quando a promessa for cumprida ou rejeitada.
$promise
for cumprido e $onFulfilledOrRejected
retornar com sucesso, $newPromise
será cumprido com o mesmo valor que $promise
.$promise
for cumprido e $onFulfilledOrRejected
lançar ou retornar uma promessa rejeitada, $newPromise
rejeitará com a exceção lançada ou o motivo da promessa rejeitada.$promise
rejeitar e $onFulfilledOrRejected
retornar com sucesso, $newPromise
rejeitará pelo mesmo motivo que $promise
.$promise
rejeitar e $onFulfilledOrRejected
lançar ou retornar uma promessa rejeitada, $newPromise
rejeitará com a exceção lançada ou o motivo da promessa rejeitada. finally()
se comporta de maneira semelhante à instrução finalmente síncrona. Quando combinado com catch()
, finally()
permite que você escreva código semelhante ao familiar par síncrono catch/finally.
Considere o seguinte código síncrono:
try {
return doSomething ();
} catch ( Throwable $ e ) {
return handleError ( $ e );
} finally {
cleanup ();
}
Código assíncrono semelhante (com doSomething()
que retorna uma promessa) pode ser escrito:
return doSomething ()
-> catch ( ' handleError ' )
-> finally ( ' cleanup ' );
$ promise -> cancel ();
O método cancel()
notifica o criador da promessa de que não há mais interesse nos resultados da operação.
Depois que uma promessa é cumprida (cumprida ou rejeitada), chamar cancel()
em uma promessa não tem efeito.
Obsoleto desde a v3.0.0, consulte
catch()
.
O método otherwise()
registra um manipulador de rejeição para uma promessa.
Este método continua a existir apenas por motivos de BC e para facilitar a atualização entre versões. É um apelido para:
$ promise -> catch ( $ onRejected );
Obsoleto desde a v3.0.0, consulte
finally()
.
O método always()
permite executar tarefas do tipo "limpeza" em uma cadeia de promessas.
Este método continua a existir apenas por motivos de BC e para facilitar a atualização entre versões. É um apelido para:
$ promise -> finally ( $ onFulfilledOrRejected );
Cria uma promessa cujo estado é controlado pelas funções passadas para $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 );
O construtor da promessa recebe uma função de resolução e uma função de cancelamento opcional, que serão chamadas com dois argumentos:
$resolve($value)
– Função primária que sela o destino da promessa retornada. Aceita um valor não prometido ou outra promessa. Quando chamado com um valor não prometido, cumpre a promessa com esse valor. Quando chamado com outra promessa, por exemplo $resolve($otherPromise)
, o destino da promessa será equivalente ao de $otherPromise
.$reject($reason)
- Função que rejeita a promessa. É recomendado apenas lançar uma exceção em vez de usar $reject()
.Se o resolvedor ou cancelador lançar uma exceção, a promessa será rejeitada com essa exceção lançada como motivo de rejeição.
A função de resolução será chamada imediatamente, a função de cancelamento apenas quando todos os consumidores chamarem o método cancel()
da promessa.
Funções úteis para criar e juntar coleções de promessas.
Todas as funções que trabalham em coleções de promessas (como all()
, race()
, etc.) suportam cancelamento. Isso significa que, se você chamar cancel()
na promessa retornada, todas as promessas da coleção serão canceladas.
$ promise = React Promise resolve (mixed $ promiseOrValue );
Cria uma promessa para o $promiseOrValue
fornecido.
Se $promiseOrValue
for um valor, será o valor de resolução da promessa retornada.
Se $promiseOrValue
for um thenable (qualquer objeto que forneça um método then()
), uma promessa confiável que segue o estado do thenable será retornada.
Se $promiseOrValue
for uma promessa, ela será retornada como está.
A $promise
resultante implementa PromiseInterface
e pode ser consumida como qualquer outra promessa:
$ 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 );
Cria uma promessa rejeitada para o $reason
fornecido.
Observe que a interface Throwable
introduzida no PHP 7 cobre erros internos do PHP Exception
e Error
do usuário. Ao impor Throwable
como motivo para rejeitar uma promessa, qualquer erro de linguagem ou exceção de usuário pode ser usado para rejeitar uma promessa.
A $promise
resultante implementa PromiseInterface
e pode ser consumida como qualquer outra promessa:
$ 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 ;
});
Observe que as promessas rejeitadas devem sempre ser tratadas de forma semelhante à forma como quaisquer exceções devem sempre ser capturadas em um bloco try
+ catch
. Se você remover a última referência a uma promessa rejeitada que não foi tratada, será relatada uma rejeição de promessa não tratada:
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 ();
Uma promessa rejeitada será considerada "tratada" se você capturar o motivo da rejeição com o método then()
, o método catch()
ou o método finally()
. Observe que cada um desses métodos retorna uma nova promessa que pode ser novamente rejeitada se você lançar novamente uma exceção.
Uma promessa rejeitada também será considerada "tratada" se você abortar a operação com o método cancel()
(que por sua vez normalmente rejeitaria a promessa se ela ainda estivesse pendente).
Veja também a função set_rejection_handler()
.
$ promise = React Promise all (iterable $ promisesOrValues );
Retorna uma promessa que será resolvida somente quando todos os itens em $promisesOrValues
forem resolvidos. O valor de resolução da promessa retornada será um array contendo os valores de resolução de cada um dos itens em $promisesOrValues
.
$ promise = React Promise race (iterable $ promisesOrValues );
Inicia uma corrida competitiva que permite um vencedor. Retorna uma promessa que é resolvida da mesma forma que a primeira promessa resolvida é resolvida.
A promessa retornada ficará infinitamente pendente se $promisesOrValues
contiver 0 itens.
$ promise = React Promise any (iterable $ promisesOrValues );
Retorna uma promessa que será resolvida quando qualquer um dos itens em $promisesOrValues
for resolvido. O valor de resolução da promessa retornada será o valor de resolução do item acionador.
A promessa retornada só será rejeitada se todos os itens em $promisesOrValues
forem rejeitados. O valor de rejeição será ReactPromiseExceptionCompositeException
que contém todos os motivos de rejeição. Os motivos de rejeição podem ser obtidos com CompositeException::getThrowables()
.
A promessa retornada também será rejeitada com ReactPromiseExceptionLengthException
se $promisesOrValues
contiver 0 itens.
React Promise set_rejection_handler(?callable $ callback ): ?callable;
Define o manipulador de rejeição global para rejeições de promessas não tratadas.
Observe que as promessas rejeitadas devem sempre ser tratadas de forma semelhante à forma como quaisquer exceções devem sempre ser capturadas em um bloco try
+ catch
. Se você remover a última referência a uma promessa rejeitada que não foi tratada, será relatada uma rejeição de promessa não tratada. Veja também a função reject()
para mais detalhes.
O argumento ?callable $callback
DEVE ser uma função de retorno de chamada válida que aceite um único argumento Throwable
ou um valor null
para restaurar o manipulador de rejeição de promessa padrão. O valor de retorno da função de retorno de chamada será ignorado e não terá efeito, então você DEVE retornar um valor void
. A função de retorno de chamada NÃO DEVE ser lançada ou o programa será encerrado com um erro fatal.
A função retorna o manipulador de rejeição anterior ou null
se estiver usando o manipulador de rejeição de promessa padrão.
O manipulador de rejeição de promessa padrão registrará uma mensagem de erro mais seu rastreamento de pilha:
// Unhandled promise rejection with RuntimeException: Unhandled in example.php:2
React Promise reject ( new RuntimeException ( ' Unhandled ' ));
O manipulador de rejeição de promessa pode ser usado para personalizar a mensagem de log ou gravar em destinos de log personalizados. Como regra geral, esta função só deve ser usada como último recurso e as rejeições de promessas são melhor tratadas com o método then()
, o método catch()
ou o método finally()
. Veja também a função reject()
para mais detalhes.
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
}
);
Alguns exemplos simples para mostrar como funciona a mecânica do encaminhamento de Promessas/A. Esses exemplos são inventados, é claro, e em uso real, as cadeias de promessas normalmente serão espalhadas por várias chamadas de função ou até mesmo por vários níveis da arquitetura de seu aplicativo.
As promessas resolvidas encaminham os valores de resolução para a próxima promessa. A primeira promessa, $deferred->promise()
, será resolvida com o valor passado para $deferred->resolve()
abaixo.
Cada chamada para then()
retorna uma nova promessa que será resolvida com o valor de retorno do manipulador anterior. Isso cria um "pipeline" de promessa.
$ 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"
As promessas rejeitadas se comportam de maneira semelhante e também funcionam de maneira semelhante ao try/catch: ao capturar uma exceção, você deve relançar para que ela se propague.
Da mesma forma, quando você lida com uma promessa rejeitada, para propagar a rejeição, "relançá-la" retornando uma promessa rejeitada ou lançando-a (já que a promessa traduz exceções lançadas em rejeições)
$ 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"
Assim como try/catch, você pode optar por propagar ou não. Misturar resoluções e rejeições ainda encaminhará os resultados do manipulador de maneira previsível.
$ 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"
A forma recomendada de instalar esta biblioteca é através do Composer. Novo no Compositor?
Este projeto segue o SemVer. Isso instalará a versão mais recente suportada deste branch:
composer require react/promise:^3.2
Consulte também o CHANGELOG para obter detalhes sobre atualizações de versão.
Este projeto visa rodar em qualquer plataforma e, portanto, não requer nenhuma extensão PHP e suporta execução em PHP 7.1 até o atual PHP 8+. É altamente recomendável usar a versão mais recente do PHP suportada para este projeto.
Estamos comprometidos em fornecer opções de suporte de longo prazo (LTS) e em fornecer um caminho de atualização tranquilo. Se estiver usando uma versão mais antiga do PHP, você pode usar o branch 2.x
(PHP 5.4+) ou o branch 1.x
(PHP 5.3+), que fornecem uma API compatível, mas não aproveitam os recursos de linguagem mais recentes. Você pode direcionar várias versões ao mesmo tempo para oferecer suporte a uma variedade maior de versões de PHP como esta:
composer require " react/promise:^3 || ^2 || ^1 "
Para executar o conjunto de testes, primeiro você precisa clonar este repositório e depois instalar todas as dependências através do Composer:
composer install
Para executar o conjunto de testes, vá até a raiz do projeto e execute:
vendor/bin/phpunit
Além disso, usamos PHPStan no nível máximo para garantir a segurança de tipo em todo o projeto:
vendor/bin/phpstan
Promise é uma versão de when.js de Brian Cavalier.
Além disso, grande parte da documentação foi portada do Wiki When.js e dos documentos da API.
Lançado sob a licença do MIT.