Event loops med ReactPHP
Kør non-blocking I/O med ReactPHP-event-loopet.
Event loops med ReactPHP er en gratis PHP Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i PHP Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. PHP Academy-kurset indeholder 4 lektioner i alt.
ReactPHP i én sætning
ReactPHP er et rent PHP-værktøjssæt uden afhængigheder til ikke-blokerende I/O, bygget omkring et enkelt event-loop. Der kræves ingen udvidelse — det fungerer med standard-PHP ved hjælp af stream_select (eller ext-event/ext-ev, når de er tilgængelige). Med det kan du skrive langvarigt kørende servere, samtidige HTTP-klienter og streaming-forløb i ren PHP.
Det globale event-loop
Moderne ReactPHP (v1.2+) viser et standard-loop via den statiske facade React\EventLoop\Loop — du behøver ikke sende en loop-instans rundt overalt. Planlæg et callback med en timer; loopet kører, indtil der ikke er mere arbejde.
<?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+Timere og periodisk arbejde
Ikke-blokerende tidsstyring erstatter sleep(). addTimer udløses én gang; addPeriodicTimer gentages. Annuller en af dem for at stoppe den. Fordi de styres af loopet, fortsætter andre opgaver med at køre, mens en timer venter.
<?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
}
});Promises til asynkrone resultater
ReactPHP returnerer et promise for enhver operation, der bliver færdig senere. Tilknyt then() for succes og et andet callback for fejl. Promises kan sammensættes, så du kan omforme og kæde resultater uden at indlejre callbacks dybt.
<?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()));Parallel HTTP med den asynkrone klient
Den store fordel er, at du kan starte mange HTTP-forespørgsler samtidigt fra én tråd. React\Http\Browser returnerer promises; React\Promise\all() venter på hele gruppen. Ti forespørgsler på ét sekund bliver færdige på cirka ét sekund, ikke ti.
<?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";
});Fibers får koden til at se synkron ud
Callback-kæder bliver hurtigt uhåndterlige. ReactPHP integreres med react/async, som bruger PHP 8.1 Fibers, så du kan bruge await() på et promise og skrive kode trin for trin. Wrapperen coroutine()/async() kører din funktion inde i en 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();En ikke-blokerende TCP-server
ReactPHP er særligt velegnet til servere. En SocketServer accepterer forbindelser og udsender hændelser; hver forbindelse er selv en ikke-blokerende stream. Én proces håndterer tusindvis af samtidige klienter.
<?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";En HTTP-server på få linjer
Serveren react/http håndterer forespørgsler med et callback, der returnerer en Response (eller et promise, der indeholder en). Da det er en vedvarende proces, initialiserer du afhængigheder én gang — men du har også selv ansvaret for hukommelseshåndteringen mellem forespørgsler.
<?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 uden buffering
ReactPHP-streams implementerer flowkontrol: Du kan føre en læsbar stream ind i en skrivbar stream med pipe(), og kørselsmiljøet begrænser automatisk hastigheden. Det lader dig flytte gigabytes med et konstant, lille hukommelsesforbrug i stedet for at indlæse filer i 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 fileDødssynden: blokering af event-loopet
Alt går i stykker, så snart du kalder en blokerende funktion i en behandler — sleep(), blokerende PDO, curl_exec eller file_get_contents på en URL. De fryser den enkelte tråd og standser alle forbindelser. Brug Reacts alternativer: Loop::addTimer til forsinkelser, clue/reactphp-* eller asynkrone database-drivere til forespørgsler og Browser til 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/coroutineBegrænsning af samtidighed
Ubegrænset forgrening kan opbruge fildeskriptorer eller overbelaste en underliggende API. ReactPHPs clue/mq-react sætter arbejde i kø med en grænse for samtidigheden og behandler N promises ad gangen, mens resten venter. Det begrænser belastningen fra dine egne udgående kald.
<?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";
});Hurtigt tjek
Hvordan holder du pause i 2 sekunder i en ReactPHP-behandler uden at påvirke samtidigheden?
Opsummering
ReactPHP bringer ikke-blokerende I/O til almindelig PHP:
- En enkelt event loop (
Loop-facaden) driver timere, sockets og streams – ingen udvidelse er nødvendig. - Operationer returnerer promises;
all()kører forespørgsler parallelt, ogreact/async+ Fibers lader dig brugeawait()til kode, der ser synkron ud. - Byg persistente TCP/HTTP-servere og streams med backpressure, der håndterer tusindvis af forbindelser pr. proces.
- Blokér aldrig event loopet – erstat
sleep/blokerende I/O med React-timere og asynkrone drivere.
Lær PHP med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 49
- Lektioner
- 195
Ofte stillede spørgsmål
Er lektionen “Event loops med ReactPHP” gratis?
Ja — hele teksten til “Event loops med ReactPHP” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af PHP Academy-kurset, skal du opgradere til CoddyKit PRO. PHP Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Event loops med ReactPHP”?
Kør non-blocking I/O med ReactPHP-event-loopet. Du øver dig i PHP Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på PHP Academy?
Der kræves ingen tidligere erfaring. PHP Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “Event loops med ReactPHP”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne PHP Academy-lektion?
Ja. Alle PHP Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- PHP's concurrency-model
- PHP 8.1 Fibers
- Event loops med ReactPHP
- Højtydende servere med Swoole