حلقات الأحداث باستخدام ReactPHP
شغّل عمليات إدخال وإخراج غير حاجبة باستخدام حلقة أحداث ReactPHP.
حلقات الأحداث باستخدام ReactPHP درس مجاني في PHP Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في PHP Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة PHP Academy 4 دروس في المجموع.
ReactPHP في جملة واحدة
ReactPHP مجموعة أدوات مكتوبة بالكامل بلغة PHP، ولا تعتمد على أي تبعيات، لإجراء عمليات إدخال وإخراج غير حاجبة، وتتمحور حول حلقة أحداث واحدة. لا تتطلب أي إضافة — فهي تعمل على PHP القياسية باستخدام stream_select (أو ext-event/ext-ev عند توفرهما). وباستخدامها، يمكنكم كتابة خوادم طويلة التشغيل وعملاء HTTP متوازيين وخطوط معالجة للبث بلغة PHP العادية.
الحلقة العامة
توفّر ReactPHP الحديثة (v1.2+) حلقة افتراضية عبر الواجهة الثابتة React\EventLoop\Loop — فلا حاجة إلى تمرير مثيل الحلقة في كل مكان. جدْولوا دالة استدعاء باستخدام مؤقت؛ وتستمر الحلقة في العمل إلى أن لا يبقى لها أي عمل آخر.
<?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+المؤقتات والعمل الدوري
يستبدل التوقيت غير الحاجب sleep(). يعمل addTimer مرة واحدة؛ بينما يتكرر addPeriodicTimer. يمكنكم إلغاء أيٍّ منهما لإيقافه. وبما أن هذه العمليات تديرها الحلقة، تستمر المهام الأخرى في العمل أثناء انتظار المؤقت.
<?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
}
});الوعود للنتائج غير المتزامنة
تعيد ReactPHP وعدًا لأي عملية تكتمل لاحقًا. أرفقوا then() بنجاح العملية، وأرفقوا بها دالة استدعاء ثانية عند الفشل. يمكن تركيب الوعود معًا، لذا يمكنكم تحويل النتائج وتسلسلها من دون تعميق دوال الاستدعاء المتداخلة.
<?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 المتوازية باستخدام العميل غير المتزامن
الفائدة الكبرى هي إطلاق العديد من طلبات HTTP بشكل متزامن من خيط واحد. تعيد React\Http\Browser وعودًا؛ وتنتظر React\Promise\all() اكتمال الدفعة بأكملها. تكتمل عشرة طلبات، يستغرق كل منها ثانية واحدة، في نحو ثانية واحدة لا عشر ثوانٍ.
<?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 الشيفرة تبدو متزامنة
تصبح سلاسل دوال الاستدعاء معقدة وغير عملية. تتكامل ReactPHP مع react/async، الذي يستخدم Fibers في PHP 8.1 لكي تتمكنوا من استخدام await() مع وعد وكتابة شيفرة خطية مباشرة. ويشغّل الغلاف coroutine()/async() دالتكم داخل 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();خادم TCP غير حاجب
تتألق ReactPHP في الخوادم. يقبل SocketServer الاتصالات ويطلق الأحداث؛ وكل اتصال هو في حد ذاته تدفق غير حاجب. تستطيع عملية واحدة التعامل مع آلاف العملاء المتصلين في الوقت نفسه.
<?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";خادم HTTP في بضعة أسطر
يعالج خادم react/http الطلبات باستخدام دالة استدعاء تعيد Response (أو وعدًا به). وبما أنه يعمل كعملية مستمرة، فإنكم تهيئون التبعيات مرة واحدة — لكنكم تتحملون أيضًا مسؤولية إدارة الذاكرة بين الطلبات.
<?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";البث من دون تخزين مؤقت
تنفذ تدفقات ReactPHP آلية الضغط العكسي: يمكنكم استخدام pipe() لتوصيل تدفق قابل للقراءة بآخر قابل للكتابة، وتتولى بيئة التشغيل تنظيم السرعة تلقائيًا. يتيح ذلك نقل غيغابايتات من البيانات مع الحفاظ على استهلاك ذاكرة ثابت وصغير بدلًا من تحميل الملفات إلى ذاكرة الوصول العشوائي.
<?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 fileالخطيئة الكبرى: حجب الحلقة
ينهار كل شيء فور استدعاء دالة حاجبة داخل معالج — مثل sleep()، وPDO الحاجب، وcurl_exec، وfile_get_contents مع عنوان URL. فهي تجمّد الخيط الوحيد وتوقف جميع الاتصالات. استخدموا بدائل React: Loop::addTimer للتأخيرات، وclue/reactphp-* أو برامج تشغيل قواعد البيانات غير المتزامنة للاستعلامات، وBrowser لطلبات 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/coroutineالحد من التزامن
قد يؤدي توزيع العمل بلا حدود إلى استنفاد واصفات الملفات أو الضغط الشديد على واجهة برمجة تطبيقات لاحقة. تضع قوائم clue/mq-react في ReactPHP حدًا للتزامن، فتعالج N من الوعود في كل مرة بينما تنتظر البقية. وبهذا تطبقون ضغطًا عكسيًا على الحمل الصادر من تطبيقكم.
<?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";
});تحقق سريع
كيف تنتظرون ثانيتين داخل معالج ReactPHP من دون الإضرار بالتزامن؟
خلاصة
توفّر ReactPHP إدخالًا وإخراجًا غير حاجبين في PHP التقليدية:
- تدير حلقة أحداث واحدة (واجهة
Loop) المؤقتات والمقابس والتدفقات — ولا تحتاج إلى أي امتداد. - تعيد العمليات وعودًا؛ وتشغّل
all()الطلبات بالتوازي، كما تتيحreact/async+ Fibers استخدامawait()للحصول على شيفرة تبدو متزامنة. - أنشئ خوادم TCP/HTTP دائمة وتدفقات ذات تحكم في الضغط العكسي تتعامل مع آلاف الاتصالات لكل عملية.
- لا تحجب الحلقة أبدًا — استبدل
sleep/عمليات الإدخال والإخراج الحاجبة بمؤقتات React وبرامج تشغيل غير متزامنة.
الأسئلة الشائعة
هل درس «حلقات الأحداث باستخدام ReactPHP» مجاني؟
نعم — نص درس «حلقات الأحداث باستخدام ReactPHP» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة PHP Academy، انتقل إلى CoddyKit PRO. تتضمن دورة PHP Academy 4 دروس في المجموع.
ماذا ستتعلم في «حلقات الأحداث باستخدام ReactPHP»؟
شغّل عمليات إدخال وإخراج غير حاجبة باستخدام حلقة أحداث ReactPHP. تتمرن على PHP Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ PHP Academy؟
لا تُشترط خبرة سابقة. PHP Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «حلقات الأحداث باستخدام ReactPHP»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس PHP Academy هذا؟
نعم. كل درس في PHP Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- نموذج التزامن في PHP
- Fibers في PHP 8.1
- حلقات الأحداث باستخدام ReactPHP
- خوادم عالية الأداء باستخدام Swoole