Signatur
Beschreibung
curl_multi_select() wartet darauf, dass mindestens eine der Verbindungen innerhalb eines cURL-Multi-Handles bereit ist, Daten zu lesen oder zu schreiben. Sie ist das PHP-Pendant zur C-Funktion select() und dient dazu, eine Busy-Wait-Schleife zu vermeiden, wenn parallele HTTP-Anfragen mit curl_multi_exec() verarbeitet werden.
Der Parameter timeout legt die maximale Wartezeit in Sekunden fest. Solange keine Verbindung bereit ist, schläft der Prozess und gibt CPU-Zeit frei. Sobald eine Verbindung aktiviert wird oder der Timeout abläuft, kehrt die Funktion zurück, und man kann curl_multi_exec() erneut aufrufen, um die Übertragungen fortzusetzen.
Ein typisches Verwendungsmuster ist eine Schleife, in der zunächst curl_multi_exec() aufgerufen wird, danach curl_multi_select(), um effizient auf weitere I/O-Ereignisse zu warten. Ohne diesen Aufruf würde eine reine while-Schleife die CPU unnötig belasten.
Bei einem Rückgabewert von -1 trat ein interner select()-Fehler auf. In diesem Fall empfiehlt es sich, kurz zu schlafen (z. B. mit usleep()), bevor man die Schleife fortsetzt, um eine potenzielle Endlosschleife unter Last zu vermeiden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $multi_handle Pflicht | CurlMultiHandle | Ein gültiges cURL-Multi-Handle, das mit curl_multi_init() erstellt wurde. |
|
| $timeout | float | 1.0 | Maximale Wartezeit in Sekunden. Darf auch einen Bruchteil einer Sekunde angeben, z. B. 0.5 für 500 Millisekunden. Wird 0 übergeben, kehrt die Funktion sofort zurück. |
Rückgabewert
0 bei Timeout, oder -1 bei einem internen Fehler von select().Beispiele
Parallele HTTP-Anfragen effizient ausführen
<?php
$urls = [
'https://example.com/api/endpoint1',
'https://example.com/api/endpoint2',
'https://example.com/api/endpoint3',
];
$multiHandle = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_multi_add_handle($multiHandle, $ch);
$handles[$i] = $ch;
}
$running = null;
do {
$status = curl_multi_exec($multiHandle, $running);
if ($running) {
// Blockiert bis zu 1 Sekunde — schont die CPU
$selected = curl_multi_select($multiHandle, 1.0);
if ($selected === -1) {
// Interner select()-Fehler: kurz schlafen, dann erneut versuchen
usleep(100);
}
}
} while ($running > 0 && $status === CURLM_OK);
foreach ($handles as $i => $ch) {
$response = curl_multi_getcontent($ch);
echo "Antwort von URL $i: " . strlen($response) . " Bytes\n";
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch);
}
curl_multi_close($multiHandle);
Sehr kurzer Timeout für nicht-blockierendes Verhalten
<?php
$mh = curl_multi_init();
$ch1 = curl_init('https://httpbin.org/delay/2');
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch1);
$running = null;
$iterations = 0;
do {
curl_multi_exec($mh, $running);
// Timeout von 50 ms: erlaubt es, zwischendurch andere Arbeit zu erledigen
$ready = curl_multi_select($mh, 0.05);
$iterations++;
// Hier könnte andere Logik ausgeführt werden ...
} while ($running > 0);
echo "Benötigte Iterationen: $iterations\n";
echo curl_multi_getcontent($ch1);
curl_multi_remove_handle($mh, $ch1);
curl_close($ch1);
curl_multi_close($mh);
// Wichtig · Fallstricke
-1-Rückgabewert: Auf manchen Systemen kann curl_multi_select() gelegentlich -1 zurückgeben, selbst ohne echten Fehler (bekannter Bug mit bestimmten libcurl-Versionen). Daher sollte die Schleife bei -1 nicht sofort abbrechen, sondern mit einem kurzen usleep() fortfahren.
Keine vollständige Alternative zu reaktiven I/O-Modellen: Für sehr viele gleichzeitige Verbindungen (Hunderte bis Tausende) sind eventbasierte Alternativen wie ReactPHP oder Amphp besser geeignet, da select() auf vielen Systemen auf 1024 Dateideskriptoren begrenzt ist.
Timeout-Präzision: Der tatsächliche Timeout kann von der Betriebssystemgenauigkeit und der internen libcurl-Zeitplanung abhängen. Sehr kleine Werte (z. B. 0.001) sind möglicherweise nicht exakt.