Event loop con ReactPHP
Eseguite I/O non bloccante con l'event loop di ReactPHP.
Event loop con ReactPHP è una lezione PHP Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento PHP Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso PHP Academy include 4 lezioni in totale.
ReactPHP in una frase
ReactPHP è un toolkit per PHP puro e privo di dipendenze per l'I/O non bloccante, basato su un singolo event loop. Non richiede estensioni: funziona con PHP standard usando stream_select (o ext-event/ext-ev quando disponibili). Con esso può scrivere server a esecuzione prolungata, client HTTP paralleli e pipeline di streaming in semplice PHP.
Il loop globale
ReactPHP moderno (v1.2+) espone un loop predefinito tramite la facciata statica React\EventLoop\Loop; non è necessario passare ovunque un'istanza del loop. Pianifichi un callback con un timer; il loop viene eseguito finché non rimane altro lavoro.
<?php
require 'vendor/autoload.php';
use React\EventLoop\Loop;
Loop::addTimer(1.0, function () {
echo "fired after 1 second\n";
});
echo "scheduled\n";
// Loop::run() is auto-invoked at script shutdown in v1.2+Timer e attività periodiche
I timer non bloccanti sostituiscono sleep(). addTimer si attiva una volta; addPeriodicTimer si ripete. Annulli ciascuno dei due per interromperlo. Poiché sono gestiti dal loop, le altre attività continuano mentre il timer attende.
<?php
use React\EventLoop\Loop;
$count = 0;
$timer = Loop::addPeriodicTimer(0.5, function () use (&$count, &$timer) {
echo 'tick ' . (++$count) . "\n";
if ($count === 4) {
Loop::cancelTimer($timer); // stop after 4 ticks
}
});Promise per i risultati asincroni
ReactPHP restituisce una promise per qualsiasi operazione che si completa in seguito. Aggiunga then() per il successo e un secondo callback per l'errore. Le promise sono componibili, quindi può trasformare e concatenare i risultati senza annidare profondamente i callback.
<?php
use React\Promise\Promise;
function asyncDouble(int $n): Promise {
return new Promise(function ($resolve) use ($n) {
\React\EventLoop\Loop::addTimer(0.1, fn() => $resolve($n * 2));
});
}
asyncDouble(21)
->then(fn($r) => printf("result: %d\n", $r)) // 42
->catch(fn(\Throwable $e) => printf("err: %s\n", $e->getMessage()));HTTP parallelo con il client asincrono
Il vantaggio principale: avviare molte richieste HTTP in concorrenza da un solo thread. React\Http\Browser restituisce promise; React\Promise\all() attende l'intero gruppo. Dieci richieste da 1 secondo terminano in ~1 secondo, non in 10.
<?php
use React\Http\Browser;
use function React\Promise\all;
$browser = new Browser();
$urls = [
'https://httpbin.org/delay/1',
'https://httpbin.org/delay/1',
'https://httpbin.org/delay/1',
];
$requests = array_map(fn($u) => $browser->get($u), $urls);
all($requests)->then(function (array $responses) {
echo 'all done: ' . count($responses) . " responses\n";
});Le Fibers rendono il codice simile a quello sincrono
Le catene di callback diventano ingestibili. ReactPHP si integra con react/async, che usa le Fibers di PHP 8.1 per consentirle di attendere una promise con await() e scrivere codice lineare. Il wrapper coroutine()/async() esegue la funzione all'interno di una Fiber.
<?php
use function React\Async\async;
use function React\Async\await;
use React\Http\Browser;
$main = async(function () {
$browser = new Browser();
$a = await($browser->get('https://httpbin.org/uuid'));
$b = await($browser->get('https://httpbin.org/uuid'));
echo (string) $a->getBody();
echo (string) $b->getBody();
});
$main();Un server TCP non bloccante
ReactPHP dà il meglio di sé con i server. Un SocketServer accetta connessioni ed emette eventi; ogni connessione è a sua volta uno stream non bloccante. Un solo processo gestisce migliaia di client simultanei.
<?php
use React\Socket\SocketServer;
use React\Socket\ConnectionInterface;
$socket = new SocketServer('127.0.0.1:8080');
$socket->on('connection', function (ConnectionInterface $conn) {
$conn->write("Welcome\n");
$conn->on('data', function ($data) use ($conn) {
$conn->write('echo: ' . $data); // streamed back, non-blocking
});
});
echo "listening on 127.0.0.1:8080\n";Un server HTTP in poche righe
Il server react/http gestisce le richieste con un callback che restituisce una Response (o una promise che la contiene). Poiché è un processo persistente, inizializza le dipendenze una sola volta, ma la gestione della memoria tra le richieste spetta a Lei.
<?php
use React\Http\HttpServer;
use React\Http\Message\Response;
use Psr\Http\Message\ServerRequestInterface;
use React\Socket\SocketServer;
$http = new HttpServer(function (ServerRequestInterface $request) {
return Response::json(['path' => $request->getUri()->getPath()]);
});
$http->listen(new SocketServer('0.0.0.0:8000'));
echo "http://0.0.0.0:8000\n";Streaming senza buffering
Gli stream di ReactPHP implementano il back-pressure: può collegare con pipe() uno stream leggibile a uno scrivibile e il runtime regola automaticamente la velocità. Ciò consente di trasferire gigabyte mantenendo un uso della memoria costante e ridotto, invece di caricare i file nella RAM.
<?php
use React\Stream\ReadableResourceStream;
use React\Stream\WritableResourceStream;
$source = new ReadableResourceStream(fopen('big.log', 'r'));
$dest = new WritableResourceStream(fopen('php://stdout', 'w'));
$source->pipe($dest); // back-pressure aware, never buffers whole fileIl peccato capitale: bloccare il loop
Tutto si rompe nel momento in cui chiama una funzione bloccante all'interno di un handler — sleep(), PDO bloccante, curl_exec, file_get_contents su un URL. Queste funzioni congelano il singolo thread e bloccano ogni connessione. Utilizzi gli equivalenti di React: Loop::addTimer per i ritardi, clue/reactphp-* o driver DB asincroni per le query, Browser per HTTP.
<?php
use React\EventLoop\Loop;
use function React\Async\await;
use React\Promise\Deferred;
// BAD: sleep(2); // freezes the entire loop
// GOOD: async delay that yields control
function delay(float $s): \React\Promise\PromiseInterface {
$d = new Deferred();
Loop::addTimer($s, fn() => $d->resolve(null));
return $d->promise();
}
// await(delay(2.0)); // inside a fiber/coroutineLimitare la concorrenza
Il fan-out senza limiti può esaurire i descrittori di file o sovraccaricare un'API a valle. clue/mq-react mette in coda il lavoro con un limite di concorrenza, elaborando N promise alla volta mentre le altre attendono. In questo modo applica il back-pressure al proprio carico in uscita.
<?php
use Clue\React\Mq\Queue;
use React\Http\Browser;
$browser = new Browser();
// At most 10 in-flight requests across 1000 URLs
$q = new Queue(10, null, fn($url) => $browser->get($url));
$promises = array_map(fn($u) => $q($u), $thousandUrls ?? []);
\React\Promise\all($promises)->then(function ($responses) {
echo 'completed ' . count($responses) . " with cap of 10\n";
});Verifica rapida
Come può mettere in pausa per 2 secondi all'interno di un handler ReactPHP senza compromettere la concorrenza?
Ripasso
ReactPHP porta l'I/O non bloccante in PHP puro:
- Un unico ciclo degli eventi (facade
Loop) gestisce timer, socket e stream: non serve alcuna estensione. - Le operazioni restituiscono promesse;
all()esegue le richieste in parallelo, mentrereact/asynce Fibers consentono di usareawait()per ottenere codice dall'aspetto sincrono. - È possibile creare server TCP/HTTP persistenti e stream soggetti a backpressure in grado di gestire migliaia di connessioni per processo.
- Non blocchi mai il ciclo: sostituisca
sleepe l'I/O bloccante con i timer di React e driver asincroni.
Impara PHP con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 49
- Lezioni
- 195
Domande Frequenti
La lezione «Event loop con ReactPHP» è gratuita?
Sì — il testo completo di «Event loop con ReactPHP» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso PHP Academy, passa a CoddyKit PRO. Il corso PHP Academy include 4 lezioni in totale.
Cosa imparerò in «Event loop con ReactPHP»?
Eseguite I/O non bloccante con l'event loop di ReactPHP. Eserciti PHP Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare PHP Academy?
Non è richiesta alcuna esperienza precedente. PHP Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Event loop con ReactPHP»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione PHP Academy?
Sì. Ogni lezione PHP Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Il modello di concorrenza di PHP
- Fibers di PHP 8.1
- Event loop con ReactPHP
- Server ad alte prestazioni con Swoole