Dynamic-Mess.com


"The world is a dynamic mess of jiggling things..."

PHP 8.1 : un petit exemple simple avec Fiber et CURL

Article posté le 05-03-2022 dans la catégorie PHP

Article mis à jour le : 05-05-2022

Un petit exemple pour expliquer comment utiliser Fiber, une des nouvelles fonctionnalités de PHP 8.1

Ce petit article n'a pas pour vocation de réexpliquer ce qu'est Fiber. Il y a déjà plein d'articles expliquant à quoi Fiber va servir et la documentation de PHP est comme à son habitude très claire pour décrire les méthodes disponibles.

Néanmoins, rappelons quelques notions importantes :

Passons maintenant à notre petit exemple concret.

Son but est de faire trois petites requêtes HTTP en parallèle. Bien entendu, nous pourrions utiliser curl_multi, natif à PHP, ou encore plus simple une librairie comme le client HTTP de Symfony, mais notre exemple ne servirait plus à rien. Non, nous allons plonger un peu en profondeur. Voici donc les étapes que nous allons suivre :

  1. nous lançons successivement trois requêtes HTTP ;
  2. elles partent vers un site perso qui utilise une temporisation sleep() pour simuler une latente réseau, d'une durée aléatoire, de 1 à 5 secondes ;
  3. elles sont faites en asynchrone grâce à notre code PHP piloté par Fiber.

Allons-y ! Notre exemple utilisera trois petits fichiers. Partons des profondeurs de ce code pour remonter vers le script principal, qui pilote le tout via des Fibers :

  1. blocking-curl-action.php
  2. raw-exec.php
  3. main.php

Voici comment cela va fonctionner : le fichier 3 utilisera le fichier 2 qui lui-même utilisera le 1 :

  1. main.php est notre script principal ;
  2. il utilise raw-exec.php pour lancer des commandes ;
  3. et ce dernier nous permet dans notre exemple de lancer les appels CURL via blocking-curl-action.php.

Commençons par le ... dernier, extrêmement simple : nous faisons un appel CURL bloquant à l'URL mentionnée plus haut. Pour nous permettre d'identifier chaque requête, nous passons un id numérique arbitraire. Enfin, quand la requête est terminée, avec succès, nous créons un petit fichier qui va nous servir de flag, nous verrons plus loin pourquoi :)

Passons maintenant au second, le code qui sera executé dans une Fiber : il s'agit d'une toute petite classe PHP qui contient une méthode exec() à laquelle on passe en paramètre le nom de notre fichier PHP à appeler de manière externe (comme si vous le lanciez manuellement dans la console), dans un autre thread. Vous remarquerez que :

  1. il attend l'id de la requête, que nous avons mentionné plus haut ;
  2. la commande exec() de PHP est redirigée vers une sortie spéciale pour être non bloquante : en gros, nous ne voulons pas attendre la fin de l'execution de la commande pour continuer le script, nous lançons la commande et chacun vit sa vie de son côté ;
  3. néanmoins, juste après, pour tirer profit de Fiber, nous faisons une boucle while() pour vérifier que la commande est bien terminée en regardant si le fameux fichier vide évoqué plus haut existe bien. Sinon, nous suspendons la Fiber pour ne pas bloquer le thread de PHP.
  4. enfin, pour la forme, nous affichons un message pour dire que la requête est terminée.

Enfin pour terminer, voici le fichier main.php qui pilote tout cela.

  1. Pour repartir de zéro, nous supprimons sauvagement (oui, vous avez vu le @...) les fichiers vides des requêtes précédentes ;
  2. nous créons des Fibers, qui vont utiliser la méthode execute() de la classe contenue dans le fichier raw-exec.php ;
  3. ensuite nous bouclons sur les Fibers, nous les remettons en route avec l'appel à resume() jusqu'à ce qu'elle soit terminées. 

Pour rappel et petite explication : l'appel à resume() est aussitôt annulé par l'appel à suspend() dans le fichier raw-exec.php si la requête HTTP n'est pas terminée. Ainsi, nous pouvons faire de l'asynchrone en attendant le résultat des trois requêtes, donc sans bloquer notre script principal. Évidemment, répétons-le, ce code est juste là à titre d'exemple, si nous avions voulu faire des appels HTTP asynchrones, nous aurions en réalité utilisé une librairie qui gère déjà tout cela.

À présent, à votre tour, vous pouvez lancer le fichier :

php main.php

Voici ce que vous devriez avoir (faites plusieurs tests, le résultat va varier).

Request with id #2 is finished
Request with id #3 is finished
Request with id #1 is finished

Cet article vous a plu? Découvrez d'autres articles :


comments powered by Disqus