Les promises sont une alternative plus puissante au Callback. Relativement peu connues au début. Elle sont maintenant en standard dans beaucoup de langage javascript ES6, python 3.2, java. Où via des librairies comme react/promise pour php
Une promise représente une valeur donc le résultat n’est pas encore connu.
Quand le résultat est connu, la promise a 3 états possibles
Pending ou Unfulfillled en Attente..
Resolved ou fulfillled Succès
Rejected ou Failed Erreur.
Un Deffered représente un travail qui n’est pas encore fini. Donc un Deferred possède une promise (une valeur pas encore connues).
Quand la valeur est connue, la promesse utilise un handler (en général ->then()) qui lui-même renvoie une promise. L’intérêt est que les promises sont chainables.
Mais essayons quelques exemples qui seront un peu plus parlant.
Pour ce faire nous allons d’abord installer react/promises
12345678910111213141516
<?phprequire__DIR__.'/vendor/autoload.php';// On crée un travail$deferred=newReact\Promise\Deferred();// On veux la promise$promise=$deferred->promise()->then(function(){echo"tout va bien \n";},function(){echo"tout va mal \n";},function(){echo"j'attends\n ";});// Le travail est un succes, on résoud la promise$deferred->resolve();
Voici ce que j’obtiens si je lance le programme.
1
toutvabien
Si je remplace $deferred->resolve() par $deferred->reject(). Le travail n’as pas marché. J’obtiens
Pour l’instant rien de bien compliqué. On peut chainer les promises
12345678910
$promise=$deferred->promise()->then(function(){echo"action 1 ok\n";})->then(function(){echo"action 2 ok\n";})->then(function(){echo"action 3 ok\n";},function(){echo"une des actions n'est pas ok..\n";});$deferred->resolve();
Le résultat
123
action1okaction2okaction3ok
Essayons avec deffered->reject()
Le résultat
1
unedesactionsn'estpasok..
Ajoutons un exception à la deuxième étape.
12345678
$promise=$deferred->promise()->then(function(){echo"action 1 ok\n";})->then(function(){thrownewException();})->then(function(){echo"action 3 ok\n";},function(){echo"une des actions n'est pas ok..\n";});
Le résultat
12
action1okunedesactionsn'estpasok..
Ajoutons une exception dans le premier, et ajoutons un cas pour gérer l’erreur
1234567891011
$promise=$deferred->promise()->then(function(){thrownew\Exception();})->then(function(){echo"action 2 ok\n";},function(){echo"l'action 1 pas ok mais on continue..\n";})->then(function(){echo"action 3 ok\n";},function(){echo"une des actions n'est pas ok..\n";});$deferred->resolve();
Le résultat
12
l'action1pasokmaisoncontinue..action3ok
Si on veux que l’erreur de l’action 1 se propage deux possibilités..
supprimer le callback d’erreur de l’action 2
Ou relancer l’exception
123456789
$promise=$deferred->promise()->then(function(){thrownew\Exception();})->then(function(){echo"action 2 ok\n";},function(){echo"l'action 1 pas ok et on stop le processus";thrownew\Exception();})->then(function(){echo"action 3 ok\n";},function(){echo"une des actions n'est pas ok..\n";});
Ce qui est intéressant dans les promises c’est que le code équivalent en procédural est pas génial.
1234567891011121314151617
$result=doAction1();try{$result=doAction1();if($result){$result2=doAction2($result);if($result2){$result3=doAction3($result3);return$result3;}else{thrownewException();}}else{throwNewException();}}catch(..){echo"une des actions n'est pas ok"}
Devient
123456
$result=$doAction1()->then(function($result1){doAction2($result1);})->then(function($result2){doAction3($result2);},function(){echo"une des actions n'est pas ok"});
C’est mieux non ?
Dans un prochain article nous nous utiliserons ce que nous avons appris avec Guzzle.