Fonction PHP mysqli_poll()
Apprenez la fonction PHP mysqli_poll() : syntaxe, paramètres, valeurs de retour et comment interroger des connexions MySQL asynchrones avec un exemple complet.
La fonction mysqli_poll() vous permet d'attendre plusieurs connexions MySQL simultanément et de savoir lesquelles ont terminé l'exécution d'une requête asynchrone. C'est le pont entre le déclenchement de requêtes non bloquantes et la collecte de leurs résultats sans bloquer tout votre script sur la plus lente.
Ce que fait mysqli_poll()
Lorsque vous exécutez une requête de la manière habituelle, PHP s'arrête et attend que MySQL réponde. Avec les requêtes asynchrones (démarrées avec le flag MYSQLI_ASYNC), la requête est envoyée mais votre script continue de s'exécuter. Le problème devient alors : comment savoir quand un résultat est prêt à être lu ? C'est ce à quoi mysqli_poll() répond.
Vous lui transmettez une liste de connexions et elle bloque jusqu'à ce qu'au moins l'une d'elles ait un résultat en attente (ou jusqu'à l'expiration d'un délai). Elle vous indique ensuite quelles connexions sont prêtes, et vous récupérez leurs résultats avec reap_async_query().
Cela est utile lorsque vous devez exécuter plusieurs requêtes indépendantes en parallèle — par exemple, interroger deux bases de données différentes ou exécuter plusieurs rapports lents simultanément. Au lieu de payer le coût de chaque requête l'une après l'autre, vous les déclenchez toutes et les laissez s'exécuter en parallèle.
Important : mysqli_poll() fonctionne uniquement avec le pilote mysqlnd. Il n'est pas disponible avec l'ancien pilote libmysql. Il est également uniquement procédural — il n'existe pas de méthode orientée objet $mysqli->poll() ; vous l'appelez toujours sous la forme mysqli_poll(...).
Syntaxe
mysqli_poll(
array &$read,
array &$error,
array &$reject,
int $seconds,
int $microseconds = 0
): int|falseParamètres
| Paramètre | Description |
|---|---|
$read | Liste des connexions à vérifier pour les résultats. Passé par référence — au retour, il est réécrit pour ne contenir que les connexions dont un résultat est prêt. |
$error | Réécrit pour contenir les connexions sur lesquelles une erreur s'est produite. |
$reject | Réécrit pour contenir les connexions qui ont été rejetées (aucune requête asynchrone en attente sur elles). |
$seconds | Nombre maximum de secondes à attendre. |
$microseconds | Microsecondes supplémentaires à attendre (optionnel, par défaut 0). |
Valeur de retour
Retourne le nombre de connexions prêtes en cas de succès, ou false en cas d'échec. Un retour de 0 signifie que le délai a expiré avant qu'une connexion ne soit prête — ce n'est pas une erreur.
Comment utiliser la fonction mysqli_poll()
Le schéma est toujours le même en trois étapes :
- Ouvrir une connexion par requête que vous souhaitez exécuter en parallèle.
- Démarrer chaque requête avec le flag
MYSQLI_ASYNCpour qu'elle ne bloque pas. - Boucler, en appelant
mysqli_poll()pour attendre la connexion qui se termine en premier, et récupérer son résultat.
<?php
// Open one connection per parallel query.
$conn1 = new mysqli("localhost", "user", "pass", "shop");
$conn2 = new mysqli("localhost", "user", "pass", "shop");
foreach ([$conn1, $conn2] as $c) {
if ($c->connect_errno) {
exit("Connect failed: " . $c->connect_error);
}
}
// Fire both queries asynchronously — neither call blocks.
$conn1->query("SELECT SLEEP(1), 'orders done' AS msg", MYSQLI_ASYNC);
$conn2->query("SELECT SLEEP(2), 'reports done' AS msg", MYSQLI_ASYNC);
$pending = [$conn1, $conn2];
while (!empty($pending)) {
// Copies that mysqli_poll() will rewrite by reference.
$read = $pending;
$error = $pending;
$reject = $pending;
// Block up to 5 seconds for at least one connection to become ready.
if (mysqli_poll($read, $error, $reject, 5) === false) {
echo "Poll failed.\n";
break;
}
// $read now holds only the connections with a result waiting.
foreach ($read as $conn) {
if ($result = $conn->reap_async_query()) {
$row = $result->fetch_assoc();
echo $row['msg'] . "\n";
$result->free();
} else {
echo "Query error: " . $conn->error . "\n";
}
// Remove this connection from the pending list.
$pending = array_filter($pending, fn($c) => $c !== $conn);
}
}
$conn1->close();
$conn2->close();
?>Même si la première requête dort pendant 1 seconde et la seconde pendant 2 secondes, le script entier se termine en environ 2 secondes, pas 3 — les deux requêtes se sont exécutées en même temps. Comme la requête d'1 seconde se termine en premier, le résultat est :
orders done
reports doneCe que fait le code, étape par étape
- Nous ouvrons deux connexions car chaque connexion ne peut exécuter qu'une seule requête asynchrone à la fois.
query(..., MYSQLI_ASYNC)envoie chaque requête et retourne immédiatement au lieu d'attendre.- Avant chaque appel à
mysqli_poll(), nous copions$pendingdans$read,$erroret$reject, car la fonction réécrit ces tableaux par référence.$readrevient en ne contenant que les connexions prêtes,$errorles connexions échouées, et$rejectcelles sans requête en attente. - Pour chaque connexion prête, nous appelons
reap_async_query()pour collecter le jeu de résultats, puis nous retirons cette connexion de$pendingpour ne plus l'interroger. - La boucle se termine une fois que toutes les requêtes ont été récupérées.
Remarque : Pour les charges de travail asynchrones complexes, envisagez des bibliothèques de boucles d'événements comme ReactPHP ou Swoole, qui offrent des architectures plus robustes que la création manuelle d'une boucle de scrutation.
Fonctions associées
reap_async_query()— collecter le résultat d'une connexion quemysqli_poll()a signalée comme prête.query()— exécuter une requête (ajoutezMYSQLI_ASYNCpour la rendre non bloquante).multi_query()— exécuter plusieurs instructions en un seul appel sur une seule connexion.connect_errno— vérifier si une tentative de connexion a échoué.
Conclusion
mysqli_poll() est l'élément qui rend les requêtes MySQL parallèles pratiques en PHP : il attend sur plusieurs connexions à la fois et vous indique lesquelles sont prêtes à être lues. Associez-le à des requêtes MYSQLI_ASYNC et à reap_async_query(), n'oubliez pas qu'il nécessite le pilote mysqlnd, et vous pourrez réduire le temps total de plusieurs requêtes indépendantes à environ le temps de la plus lente.