حلقة حدث المفاعل الأساسية لـ ReactPHP والتي يمكن للمكتبات استخدامها للإدخال/الإخراج المحدث.
الإصدار التطويري: يحتوي هذا الفرع على الكود الخاص بإصدار v3 القادم. للحصول على كود الإصدار v1 المستقر الحالي، قم بمراجعة الفرع
1.x
سيكون الإصدار v3 القادم هو الطريق للمضي قدمًا لهذه الحزمة. ومع ذلك، سنستمر في دعم الإصدار الأول بشكل نشط لأولئك الذين لم يستخدموا الإصدار الأحدث بعد. انظر أيضًا تعليمات التثبيت لمزيد من التفاصيل.
لكي تكون المكتبات غير المتزامنة قابلة للتشغيل المتبادل، فإنها تحتاج إلى استخدام نفس حلقة الحدث. يوفر هذا المكون واجهة LoopInterface
شائعة يمكن لأي مكتبة استهدافها. وهذا يسمح باستخدامها في نفس الحلقة، مع استدعاء run()
واحد يتحكم فيه المستخدم.
جدول المحتويات
مثال البدء السريع
الاستخدام
يجري()
قف()
addTimer()
addPeriodicTimer()
إلغاء الموقت ()
علامة المستقبل()
إضافة إشارة ()
إزالة الإشارة ()
addReadStream()
addWriteStream()
إزالةReadStream ()
إزالةWriteStream ()
StreamSelectLoop
ExtEventLoop
ExtEvLoop
ExtUvLoop
طرق الحلقة
حلقة التشغيل التلقائي
يحصل()
حلقة
تطبيقات الحلقة
واجهة الحلقة
ثَبَّتَ
الاختبارات
رخصة
أكثر
فيما يلي خادم HTTP غير متزامن تم إنشاؤه باستخدام حلقة الحدث فقط.
<?phpuse ReactEventLoopLoop;تتطلب __DIR__ . '/vendor/autoload.php';$server =stream_socket_server('tcp://127.0.0.1:8080');stream_set_blocking($server, false); Loop::addReadStream($server, function ($server) {$conn =stream_socket_accept($server);$data = "HTTP/1.1 200 OKrnContent-Length: 3rnrnHin"; Loop::addWriteStream($conn, function ($conn) use (&$data) {$writer = fwrite($conn, $data);if ($writer === strlen($data)) {fإغلاق($conn) ); حلقة::removeWriteStream($conn); } else {$data = substr($data, $writer); } }); }); Loop::addPeriodicTimer(5, function () {$memory = Memory_get_usage() / 1024;$formatted = number_format($memory, 3).'K';echo "استخدام الذاكرة الحالي: {$formatted}n"; });
انظر أيضا الأمثلة.
ستستخدم التطبيقات النموذجية فئة Loop
لاستخدام حلقة الحدث الافتراضية مثل هذا:
استخدم ReactEventLoopLoop;$timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' .PHP_EOL; }); حلقة::addTimer(1.0، الوظيفة () استخدم ($timer) { حلقة::cancelTimer($timer);echo 'Done' . PHP_EOL; });
كبديل، يمكنك أيضًا إنشاء نسخة حلقة حدث بشكل صريح في البداية، وإعادة استخدامها خلال برنامجك وتشغيلها أخيرًا في نهاية البرنامج مثل هذا:
$loop = ReactEventLoopLoop::get();$timer = $loop->addPeriodicTimer(0.1, function () {echo 'Tick' .PHP_EOL; });$loop->addTimer(1.0, function () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Done' . PHP_EOL; });$loop->run();
وفي حين أن الأول أكثر إيجازا، فإن الأخير أكثر وضوحا. وفي كلتا الحالتين، سيقوم البرنامج بتنفيذ نفس الخطوات بالضبط.
يتم إنشاء مثيل حلقة الحدث في بداية البرنامج. يتم ذلك ضمنيًا في المرة الأولى التي تقوم فيها باستدعاء فئة Loop
(أو عن طريق إنشاء مثيل لأي من تطبيقات الحلقة يدويًا).
يتم استخدام حلقة الحدث مباشرة أو تمريرها كمثيل للمكتبة ورمز التطبيق. في هذا المثال، يتم تسجيل مؤقت دوري في حلقة الحدث التي تقوم ببساطة بإخراج Tick
كل جزء من الثانية حتى يقوم مؤقت آخر بإيقاف المؤقت الدوري بعد ثانية.
يتم تشغيل حلقة الحدث في نهاية البرنامج. يتم ذلك تلقائيًا عند استخدام فئة Loop
أو بشكل صريح من خلال استدعاء run()
واحد في نهاية البرنامج.
بدءًا من v1.2.0
، نوصي بشدة باستخدام فئة Loop
. لا تزال تعليمات الحلقة الصريحة صالحة وقد تظل مفيدة في بعض التطبيقات، خاصة لفترة انتقالية نحو النمط الأكثر إيجازًا.
توجد فئة Loop
كملحق عالمي مناسب لحلقة الحدث.
توفر فئة Loop
كافة الأساليب الموجودة على LoopInterface
كطرق ثابتة:
يجري()
قف()
addTimer()
addPeriodicTimer()
إلغاء الموقت ()
علامة المستقبل()
إضافة إشارة ()
إزالة الإشارة ()
addReadStream()
addWriteStream()
إزالةReadStream ()
إزالةWriteStream ()
إذا كنت تعمل مع حلقة الحدث في كود التطبيق الخاص بك، فغالبًا ما يكون من الأسهل التعامل مباشرة مع الأساليب الثابتة المحددة في فئة Loop
مثل هذا:
استخدم ReactEventLoopLoop;$timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' .PHP_EOL; }); حلقة::addTimer(1.0، الوظيفة () استخدم ($timer) { حلقة::cancelTimer($timer);echo 'Done' . PHP_EOL; });
من ناحية أخرى، إذا كنت على دراية بالبرمجة الموجهة للكائنات (OOP) وحقن التبعية (DI)، فقد ترغب في إدخال مثيل حلقة الحدث واستدعاء أساليب المثيل على LoopInterface
مثل هذا:
استخدم ReactEventLoopLoop؛ استخدم ReactEventLoopLoopInterface؛ فئة Greeter {حلقة $ خاصة؛ وظيفة عامة __construct (LoopInterface $loop) {$this->loop = $loop; }تحية الوظيفة العامة (سلسلة $name) {$this->loop->addTimer(1.0, function () use ($name) {echo 'Hello ' . $name .'!' . PHP_EOL; }); } }$greeter = new Greeter(Loop::get());$greeter->greet('Alice');$greeter->greet('Bob');
ستتم إعادة توجيه كل استدعاء أسلوب ثابت كما هو إلى مثيل حلقة الحدث الأساسي باستخدام استدعاء Loop::get()
داخليًا. راجع LoopInterface
لمزيد من التفاصيل حول الطرق المتاحة.
عند استخدام فئة Loop
، سيتم تنفيذ الحلقة تلقائيًا في نهاية البرنامج. وهذا يعني أن المثال التالي سيجدول مؤقتًا وسينفذ البرنامج تلقائيًا حتى يتم إطلاق حدث المؤقت:
استخدم ReactEventLoopLoop؛ Loop::addTimer(1.0, function () {echo 'Hello' . PHP_EOL; });
اعتبارًا من v1.2.0
، نوصي بشدة باستخدام فئة Loop
بهذه الطريقة وحذف أي استدعاءات صريحة run()
. لأسباب BC، لا تزال طريقة run()
الصريحة صالحة وقد تظل مفيدة في بعض التطبيقات، خاصة لفترة انتقالية نحو النمط الأكثر إيجازًا.
إذا كنت لا تريد تشغيل Loop
تلقائيًا، فيمكنك run()
أو stop()
. يمكن أن يكون هذا مفيدًا إذا كنت تستخدم معالج استثناء عالميًا مثل هذا:
استخدم ReactEventLoopLoop؛ Loop::addTimer(10.0, function () {echo "لا يحدث أبدًا"; });set_exception_handler(function (Throwable $e) {echo 'Error:' . $e->getMessage() . PHP_EOL; حلقة::توقف(); });طرح RuntimeException الجديد('Demo');
يمكن استخدام طريقة get(): LoopInterface
للحصول على مثيل حلقة الحدث النشط حاليًا.
ستعيد هذه الطريقة دائمًا نفس مثيل حلقة الحدث طوال عمر التطبيق الخاص بك.
use ReactEventLoopLoop;use ReactEventLoopLoopInterface;$loop = Loop::get();assert($loop مثيل LoopInterface);assert($loop === Loop::get());
يعد هذا مفيدًا بشكل خاص إذا كنت تستخدم البرمجة الموجهة للكائنات (OOP) وحقن التبعية (DI). في هذه الحالة، قد ترغب في إدخال نسخة حلقة حدث واستدعاء أساليب المثيل على LoopInterface
مثل هذا:
استخدم ReactEventLoopLoop؛ استخدم ReactEventLoopLoopInterface؛ فئة Greeter {حلقة $ خاصة؛ وظيفة عامة __construct (LoopInterface $loop) {$this->loop = $loop; }تحية الوظيفة العامة (سلسلة $name) {$this->loop->addTimer(1.0, function () use ($name) {echo 'Hello ' . $name .'!' . PHP_EOL; }); } }$greeter = new Greeter(Loop::get());$greeter->greet('Alice');$greeter->greet('Bob');
راجع LoopInterface
لمزيد من التفاصيل حول الطرق المتاحة.
بالإضافة إلى LoopInterface
، هناك عدد من تطبيقات حلقة الأحداث المتوفرة.
تدعم جميع حلقات الأحداث هذه الميزات:
الاقتراع واصف الملف
توقيت لمرة واحدة
توقيتات دورية
التنفيذ المؤجل على علامة الحلقة المستقبلية
بالنسبة لمعظم مستهلكي هذه الحزمة، فإن تنفيذ حلقة الحدث الأساسية هو تفاصيل التنفيذ. يجب عليك استخدام فئة Loop
لإنشاء مثيل جديد تلقائيًا.
متقدم! إذا كنت بحاجة بشكل صريح إلى تنفيذ حلقة حدث معينة، فيمكنك إنشاء مثيل لأحد الفئات التالية يدويًا. لاحظ أنه قد يتعين عليك تثبيت ملحقات PHP المطلوبة لتنفيذ حلقة الحدث المعنية أولاً وإلا فإنها ستطرح BadMethodCallException
عند الإنشاء.
حلقة حدث تعتمد على stream_select()
.
يستخدم هذا الدالة stream_select()
وهو التطبيق الوحيد الذي يعمل خارج الصندوق مع PHP.
تعمل حلقة الحدث هذه خارج الصندوق على أي إصدار PHP. وهذا يعني أنه لا يلزم التثبيت وأن هذه المكتبة تعمل على جميع الأنظمة الأساسية وإصدارات PHP المدعومة. وفقًا لذلك، ستستخدم فئة Loop
حلقة الحدث هذه بشكل افتراضي إذا لم تقم بتثبيت أي من ملحقات حلقة الحدث المذكورة أدناه.
تحت الغطاء، يقوم بإجراء مكالمة نظام select
بسيطة. يقتصر استدعاء النظام هذا على الحد الأقصى لعدد واصف الملف وهو FD_SETSIZE
(يعتمد على النظام الأساسي، عادةً 1024) ويتم قياسه باستخدام O(m)
( m
هو الحد الأقصى لعدد واصف الملف الذي تم تمريره). هذا يعني أنك قد تواجه مشكلات عند التعامل مع آلاف التدفقات بشكل متزامن وقد ترغب في النظر في استخدام أحد تطبيقات حلقة الأحداث البديلة المدرجة أدناه في هذه الحالة. إذا كانت حالة الاستخدام الخاصة بك من بين العديد من حالات الاستخدام الشائعة التي تتضمن التعامل مع العشرات أو بضع مئات من التدفقات فقط في وقت واحد، فإن تنفيذ حلقة الحدث هذا يعمل بشكل جيد حقًا.
إذا كنت تريد استخدام معالجة الإشارة (انظر أيضًا addSignal()
أدناه)، فإن تنفيذ حلقة الحدث يتطلب ext-pcntl
. هذا الامتداد متاح فقط للأنظمة الأساسية المشابهة لنظام Unix ولا يدعم Windows. يتم تثبيته بشكل شائع كجزء من العديد من توزيعات PHP. إذا كان هذا الامتداد مفقودًا (أو كنت تعمل على نظام التشغيل Windows)، فلن تكون معالجة الإشارة مدعومة وسيتم طرح BadMethodCallException
بدلاً من ذلك.
من المعروف أن حلقة الحدث هذه تعتمد على وقت ساعة الحائط لجدولة المؤقتات المستقبلية عند استخدام أي إصدار قبل PHP 7.3، لأن مصدر الوقت الرتيب متاح فقط اعتبارًا من PHP 7.3 ( hrtime()
). على الرغم من أن هذا لا يؤثر على العديد من حالات الاستخدام الشائعة، إلا أن هذا يعد تمييزًا مهمًا للبرامج التي تعتمد على دقة زمنية عالية أو على الأنظمة التي تخضع لتعديلات زمنية متقطعة (قفزات زمنية). هذا يعني أنه إذا قمت بجدولة مؤقت للتشغيل خلال 30 ثانية على PHP <7.3 ثم ضبطت وقت النظام الخاص بك للأمام بمقدار 20 ثانية، فقد يتم تشغيل المؤقت خلال 10 ثوانٍ. راجع أيضًا addTimer()
لمزيد من التفاصيل.
حلقة حدث مبنية على ext-event
.
يستخدم هذا ملحق event
PECL، الذي يوفر واجهة لمكتبة libevent
. يدعم libevent
نفسه عددًا من الواجهات الخلفية الخاصة بالنظام (epoll، kqueue).
من المعروف أن هذه الحلقة تعمل مع PHP 7.1 حتى PHP 8+.
حلقة حدث مبنية على ext-ev
.
تستخدم هذه الحلقة امتداد ev
PECL، الذي يوفر واجهة لمكتبة libev
. يدعم libev
نفسه عددًا من الواجهات الخلفية الخاصة بالنظام (epoll، kqueue).
من المعروف أن هذه الحلقة تعمل مع PHP 7.1 حتى PHP 8+.
حلقة حدث تعتمد ext-uv
.
تستخدم هذه الحلقة امتداد uv
PECL، الذي يوفر واجهة لمكتبة libuv
. يدعم libuv
نفسه عددًا من الواجهات الخلفية الخاصة بالنظام (epoll، kqueue).
من المعروف أن هذه الحلقة تعمل مع PHP 7.1 حتى PHP 8+.
يمكن استخدام الأسلوب run(): void
لتشغيل حلقة الحدث حتى لا يكون هناك المزيد من المهام المطلوب تنفيذها.
بالنسبة للعديد من التطبيقات، هذه الطريقة هي الاستدعاء الوحيد المرئي مباشرة في حلقة الحدث. كقاعدة عامة، يوصى عادةً بإرفاق كل شيء بنفس مثيل الحلقة ثم تشغيل الحلقة مرة واحدة في الطرف السفلي من التطبيق.
$loop->run();
ستحافظ هذه الطريقة على تشغيل الحلقة حتى لا يكون هناك المزيد من المهام المطلوب تنفيذها. بمعنى آخر: سيتم حظر هذه الطريقة حتى تتم إزالة المؤقت و/أو البث و/أو الإشارة الأخيرة.
وبالمثل، من الضروري التأكد من أن التطبيق يستدعي هذه الطريقة فعليًا مرة واحدة. ستؤدي إضافة المستمعين إلى الحلقة وعدم تشغيلها فعليًا إلى خروج التطبيق دون الانتظار فعليًا لأي من المستمعين المرفقين.
يجب عدم استدعاء هذه الطريقة أثناء تشغيل الحلقة بالفعل. قد يتم استدعاء هذه الطريقة أكثر من مرة بعد أن تم stop()
أو بعد توقفها تلقائيًا لأنها لم تعد لديها أي شيء لتفعله في السابق.
يمكن استخدام الأسلوب stop(): void
لتوجيه حلقة حدث قيد التشغيل للتوقف.
تعتبر هذه الطريقة استخدامًا متقدمًا ويجب استخدامها بحذر. كقاعدة عامة، يُنصح عادةً بترك الحلقة تتوقف تلقائيًا فقط عندما لا يكون لديها أي شيء لتفعله.
يمكن استخدام هذه الطريقة لتوجيه حلقة الحدث بشكل صريح للتوقف:
$loop->addTimer(3.0, function () use ($loop) {$loop->stop(); });
إن استدعاء هذا الأسلوب على مثيل حلقة غير قيد التشغيل حاليًا أو على مثيل حلقة تم إيقافه بالفعل ليس له أي تأثير.
يمكن استخدام أسلوب addTimer(float $interval, callable $callback): TimerInterface
لإدراج رد اتصال ليتم استدعاؤه مرة واحدة بعد الفاصل الزمني المحدد.
يجب أن تكون المعلمة الثانية وظيفة رد اتصال مؤقت تقبل مثيل المؤقت كمعلمة وحيدة. إذا كنت لا تستخدم مثيل المؤقت داخل وظيفة رد اتصال المؤقت، فيمكنك استخدام وظيفة لا تحتوي على معلمات على الإطلاق.
يجب ألا تقوم وظيفة رد اتصال المؤقت بطرح Exception
. سيتم تجاهل القيمة المرجعة لوظيفة رد اتصال المؤقت ولن يكون لها أي تأثير، لذا، لأسباب تتعلق بالأداء، يوصى بعدم إرجاع أي بنيات بيانات زائدة.
تقوم هذه الطريقة بإرجاع مثيل مؤقت. سيتم أيضًا تمرير نفس مثيل المؤقت إلى وظيفة رد اتصال المؤقت كما هو موضح أعلاه. يمكنك استدعاء cancelTimer
لإلغاء مؤقت معلق. على عكس addPeriodicTimer()
، ستضمن هذه الطريقة استدعاء رد الاتصال مرة واحدة فقط بعد الفاصل الزمني المحدد.
$loop->addTimer(0.8, function () {echo 'world!' . PHP_EOL; });$loop->addTimer(0.3, function () {echo 'hello'; });
انظر أيضًا المثال رقم 1.
إذا كنت تريد الوصول إلى أي متغيرات ضمن وظيفة رد الاتصال الخاصة بك، فيمكنك ربط البيانات التعسفية بإغلاق رد الاتصال مثل هذا:
وظيفة مرحبا(اسم $، LoopInterface $loop) {$loop->addTimer(1.0, function () use ($name) {echo "hello $namen"; }); }hello('اختبار', $loop);
لا تفرض هذه الواجهة أي دقة مؤقت معينة، لذا قد يلزم اتخاذ رعاية خاصة إذا كنت تعتمد على دقة عالية جدًا بدقة بالمللي ثانية أو أقل. يجب أن تعمل تطبيقات حلقة الأحداث على أساس أفضل جهد ويجب أن توفر دقة بالمللي ثانية على الأقل ما لم يُذكر خلاف ذلك. من المعروف أن العديد من تطبيقات حلقة الأحداث الحالية توفر دقة ميكروثانية، ولكن لا يُنصح عمومًا بالاعتماد على هذه الدقة العالية.
وبالمثل، فإن ترتيب تنفيذ الموقتات المقرر تنفيذها في نفس الوقت (ضمن دقتها الممكنة) غير مضمون.
تقترح هذه الواجهة أن تطبيقات حلقة الأحداث يجب أن تستخدم مصدرًا زمنيًا رتيبًا إذا كان متاحًا. نظرًا لأن مصدر الوقت الرتيب متاح فقط اعتبارًا من PHP 7.3 بشكل افتراضي، فقد تتراجع تطبيقات حلقة الأحداث إلى استخدام وقت ساعة الحائط. على الرغم من أن هذا لا يؤثر على العديد من حالات الاستخدام الشائعة، إلا أن هذا يعد تمييزًا مهمًا للبرامج التي تعتمد على دقة زمنية عالية أو على الأنظمة التي تخضع لتعديلات زمنية متقطعة (قفزات زمنية). هذا يعني أنه إذا قمت بجدولة مؤقت للتشغيل خلال 30 ثانية ثم قمت بضبط وقت النظام الخاص بك للأمام بمقدار 20 ثانية، فيجب أن يستمر تشغيل المؤقت خلال 30 ثانية. راجع أيضًا تطبيقات حلقة الأحداث لمزيد من التفاصيل.
addPeriodicTimer(float $interval, callable $callback): TimerInterface
لإدراج رد اتصال ليتم استدعاؤه بشكل متكرر بعد الفاصل الزمني المحدد.
يجب أن تكون المعلمة الثانية وظيفة رد اتصال مؤقت تقبل مثيل المؤقت كمعلمة وحيدة. إذا كنت لا تستخدم مثيل المؤقت داخل وظيفة رد اتصال المؤقت، فيمكنك استخدام وظيفة لا تحتوي على معلمات على الإطلاق.
يجب ألا تقوم وظيفة رد اتصال المؤقت بطرح Exception
. سيتم تجاهل القيمة المرجعة لوظيفة رد اتصال المؤقت ولن يكون لها أي تأثير، لذا، لأسباب تتعلق بالأداء، يوصى بعدم إرجاع أي بنيات بيانات زائدة.
تقوم هذه الطريقة بإرجاع مثيل مؤقت. سيتم أيضًا تمرير نفس مثيل المؤقت إلى وظيفة رد اتصال المؤقت كما هو موضح أعلاه. على عكس addTimer()
، ستضمن هذه الطريقة استدعاء رد الاتصال بشكل لا نهائي بعد الفاصل الزمني المحدد أو حتى تقوم باستدعاء cancelTimer
.
$timer = $loop->addPeriodicTimer(0.1, function () {echo 'tick!' . PHP_EOL; });$loop->addTimer(1.0, function () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Done' . PHP_EOL; });
انظر أيضًا المثال رقم 2.
إذا كنت تريد الحد من عدد عمليات التنفيذ، فيمكنك ربط البيانات التعسفية بإغلاق رد الاتصال مثل هذا:
وظيفة مرحبا(اسم $، LoopInterface $loop) {$n = 3;$loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {if ($n > 0) { --$n;echo "hello $namen"; } else {$loop->cancelTimer($timer); } }); }hello('اختبار', $loop);
لا تفرض هذه الواجهة أي دقة مؤقت معينة، لذا قد يلزم اتخاذ رعاية خاصة إذا كنت تعتمد على دقة عالية جدًا بدقة بالمللي ثانية أو أقل. يجب أن تعمل تطبيقات حلقة الأحداث على أساس أفضل جهد ويجب أن توفر دقة بالمللي ثانية على الأقل ما لم يُذكر خلاف ذلك. من المعروف أن العديد من تطبيقات حلقة الأحداث الحالية توفر دقة ميكروثانية، ولكن لا يُنصح عمومًا بالاعتماد على هذه الدقة العالية.
وبالمثل، فإن ترتيب تنفيذ الموقتات المقرر تنفيذها في نفس الوقت (ضمن دقتها الممكنة) غير مضمون.
تقترح هذه الواجهة أن تطبيقات حلقة الأحداث يجب أن تستخدم مصدرًا زمنيًا رتيبًا إذا كان متاحًا. نظرًا لأن مصدر الوقت الرتيب متاح فقط اعتبارًا من PHP 7.3 بشكل افتراضي، فقد تتراجع تطبيقات حلقة الأحداث إلى استخدام وقت ساعة الحائط. على الرغم من أن هذا لا يؤثر على العديد من حالات الاستخدام الشائعة، إلا أن هذا يعد تمييزًا مهمًا للبرامج التي تعتمد على دقة زمنية عالية أو على الأنظمة التي تخضع لتعديلات زمنية متقطعة (قفزات زمنية). هذا يعني أنه إذا قمت بجدولة مؤقت للتشغيل خلال 30 ثانية ثم قمت بضبط وقت النظام الخاص بك للأمام بمقدار 20 ثانية، فيجب أن يستمر تشغيل المؤقت خلال 30 ثانية. راجع أيضًا تطبيقات حلقة الأحداث لمزيد من التفاصيل.
بالإضافة إلى ذلك، قد تخضع المؤقتات الدورية لانحراف المؤقت بسبب إعادة الجدولة بعد كل استدعاء. على هذا النحو، لا يُنصح عمومًا بالاعتماد على ذلك لفترات زمنية عالية الدقة بدقة ميلي ثانية أو أقل.
يمكن استخدام طريقة cancelTimer(TimerInterface $timer): void
لإلغاء مؤقت معلق.
راجع أيضًا addPeriodicTimer()
والمثال رقم 2.
إن استدعاء هذه الطريقة على مثيل مؤقت لم تتم إضافته إلى مثيل الحلقة هذا أو على مؤقت تم إلغاؤه بالفعل ليس له أي تأثير.
يمكن استخدام التابع futureTick(callable $listener): void
لجدولة رد اتصال ليتم استدعاؤه عند علامة التجزئة المستقبلية لحلقة الحدث.
يعمل هذا بشكل مشابه جدًا للمؤقتات ذات الفاصل الزمني صفر ثانية، ولكنه لا يتطلب الحمل الزائد لجدولة قائمة انتظار المؤقت.
يجب أن تكون وظيفة رد اتصال التجزئة قادرة على قبول صفر معلمات.
يجب ألا تقوم وظيفة رد الاتصال بطرح Exception
. سيتم تجاهل القيمة المرجعة لوظيفة رد اتصال التجزئة ولن يكون لها أي تأثير، لذا، لأسباب تتعلق بالأداء، يوصى بعدم إرجاع أي بنيات بيانات زائدة.
إذا كنت تريد الوصول إلى أي متغيرات ضمن وظيفة رد الاتصال الخاصة بك، فيمكنك ربط البيانات التعسفية بإغلاق رد الاتصال مثل هذا:
وظيفة مرحبا(اسم $، LoopInterface $loop) {$loop->futureTick(function () use ($name) {echo "hello $namen"; }); }hello('اختبار', $loop);
على عكس أجهزة ضبط الوقت، يتم ضمان تنفيذ عمليات رد النداء بالترتيب الذي تم وضعه في قائمة الانتظار. وأيضًا، بمجرد وضع رد الاتصال في قائمة الانتظار، لا توجد طريقة لإلغاء هذه العملية.
يُستخدم هذا غالبًا لتقسيم المهام الأكبر إلى خطوات أصغر (شكل من أشكال المهام التعاونية المتعددة).
$loop->futureTick(function () {echo 'b'; });$loop->futureTick(function () {echo 'c'; });صدى 'أ';
انظر أيضًا المثال رقم 3.
يمكن استخدام الأسلوب addSignal(int $signal, callable $listener): void
لتسجيل المستمع ليتم إعلامه عند التقاط إشارة من خلال هذه العملية.
يعد هذا مفيدًا لالتقاط إشارات مقاطعة المستخدم أو إشارات إيقاف التشغيل من أدوات مثل supervisor
أو systemd
.
يجب أن تكون المعلمة الثانية وظيفة رد اتصال مستمع تقبل الإشارة كمعلمة وحيدة. إذا كنت لا تستخدم الإشارة داخل وظيفة رد اتصال المستمع، فيمكنك استخدام وظيفة لا تحتوي على معلمات على الإطلاق.
يجب ألا تقوم وظيفة رد اتصال المستمع بطرح Exception
. سيتم تجاهل قيمة الإرجاع الخاصة بوظيفة رد اتصال المستمع ولن يكون لها أي تأثير، لذا، لأسباب تتعلق بالأداء، يوصى بعدم إرجاع أي بنيات بيانات زائدة.
$loop->addSignal(SIGINT, function (int $signal) {echo "تم التقاط إشارة مقاطعة المستخدم" . PHP_EOL; });
انظر أيضًا المثال رقم 4.
الإشارات متاحة فقط على الأنظمة الأساسية المشابهة لـ Unix، ولا يتم دعم Windows بسبب قيود نظام التشغيل. قد تطرح هذه الطريقة BadMethodCallException
إذا كانت الإشارات غير مدعومة على هذا النظام الأساسي، على سبيل المثال عندما تكون الملحقات المطلوبة مفقودة.
ملاحظة: يمكن إضافة المستمع مرة واحدة فقط لنفس الإشارة، وأي محاولة لإضافته أكثر من مرة سيتم تجاهلها.
يمكن استخدام الأسلوب removeSignal(int $signal, callable $listener): void
لإزالة مستمع الإشارة المُضاف مسبقًا.
$loop->removeSignal(SIGINT, $listener);
سيتم تجاهل أي محاولات لإزالة المستمعين غير المسجلين.
متقدم! لاحظ أن واجهة برمجة التطبيقات ذات المستوى المنخفض هذه تعتبر استخدامًا متقدمًا. من المحتمل أن تستخدم معظم حالات الاستخدام واجهة برمجة التطبيقات Stream API ذات المستوى الأعلى القابلة للقراءة بدلاً من ذلك.
يمكن استخدام الأسلوب addReadStream(resource $stream, callable $callback): void
لتسجيل المستمع ليتم إعلامه عندما يكون الدفق جاهزًا للقراءة.
يجب أن تكون المعلمة الأولى مورد دفق صالحًا يدعم التحقق مما إذا كان جاهزًا للقراءة من خلال تنفيذ هذه الحلقة. يجب عدم إضافة مورد دفق واحد أكثر من مرة. بدلاً من ذلك، إما أن تقوم باستدعاء removeReadStream()
أولاً أو التفاعل مع هذا الحدث باستخدام مستمع واحد ثم الإرسال من هذا المستمع. قد تطرح هذه الطريقة Exception
إذا كان نوع المورد المحدد غير مدعوم من خلال تنفيذ هذه الحلقة.
يجب أن تكون المعلمة الثانية وظيفة رد اتصال مستمع تقبل مورد الدفق كمعلمة وحيدة. إذا كنت لا تستخدم مورد الدفق داخل وظيفة رد اتصال المستمع، فيمكنك استخدام وظيفة لا تحتوي على معلمات على الإطلاق.
يجب ألا تقوم وظيفة رد اتصال المستمع بطرح Exception
. سيتم تجاهل قيمة الإرجاع الخاصة بوظيفة رد اتصال المستمع ولن يكون لها أي تأثير، لذا، لأسباب تتعلق بالأداء، يوصى بعدم إرجاع أي بنيات بيانات زائدة.
إذا كنت تريد الوصول إلى أي متغيرات ضمن وظيفة رد الاتصال الخاصة بك، فيمكنك ربط البيانات التعسفية بإغلاق رد الاتصال مثل هذا:
$loop->addReadStream($stream, function ($stream) use ($name) {echo $name .' قال: ' . fread($stream); });
انظر أيضًا المثال رقم 11.
يمكنك استدعاء removeReadStream()
لإزالة مستمع حدث القراءة لهذا الدفق.
لا يتم ضمان ترتيب تنفيذ المستمعين عندما تصبح التدفقات المتعددة جاهزة في نفس الوقت.
من المعروف أن بعض تطبيقات حلقة الأحداث تقوم بتشغيل المستمع فقط إذا أصبح الدفق قابلاً للقراءة (يتم تشغيله بواسطة الحافة) وقد لا يتم تشغيله إذا كان الدفق قابلاً للقراءة بالفعل من البداية. وهذا يعني أيضًا أنه قد لا يتم التعرف على التدفق باعتباره قابلاً للقراءة عندما تظل البيانات في مخازن التدفق الداخلية لـ PHP. على هذا النحو، يوصى باستخدام stream_set_read_buffer($stream, 0);
لتعطيل المخزن المؤقت للقراءة الداخلي لـ PHP في هذه الحالة.
متقدم! لاحظ أن واجهة برمجة التطبيقات ذات المستوى المنخفض هذه تعتبر استخدامًا متقدمًا. من المحتمل أن تستخدم معظم حالات الاستخدام واجهة برمجة التطبيقات Stream API ذات المستوى الأعلى القابلة للكتابة بدلاً من ذلك.
يمكن استخدام الأسلوب addWriteStream(resource $stream, callable $callback): void
لتسجيل المستمع ليتم إعلامه عندما يكون الدفق جاهزًا للكتابة.
يجب أن تكون المعلمة الأولى مورد دفق صالحًا يدعم التحقق مما إذا كان جاهزًا للكتابة من خلال تنفيذ هذه الحلقة. يجب عدم إضافة مورد دفق واحد أكثر من مرة. بدلاً من ذلك، إما أن تقوم باستدعاء removeWriteStream()
أولاً أو التفاعل مع هذا الحدث باستخدام مستمع واحد ثم الإرسال من هذا المستمع. قد تطرح هذه الطريقة Exception
إذا كان نوع المورد المحدد غير مدعوم من خلال تنفيذ هذه الحلقة.
يجب أن تكون المعلمة الثانية وظيفة رد اتصال مستمع تقبل مورد الدفق كمعلمة وحيدة. إذا كنت لا تستخدم مورد الدفق داخل وظيفة رد اتصال المستمع، فيمكنك استخدام وظيفة لا تحتوي على معلمات على الإطلاق.
يجب ألا تقوم وظيفة رد اتصال المستمع بطرح Exception
. سيتم تجاهل قيمة الإرجاع الخاصة بوظيفة رد اتصال المستمع ولن يكون لها أي تأثير، لذا، لأسباب تتعلق بالأداء، يوصى بعدم إرجاع أي بنيات بيانات زائدة.
إذا كنت تريد الوصول إلى أي متغيرات ضمن وظيفة رد الاتصال الخاصة بك، فيمكنك ربط البيانات التعسفية بإغلاق رد الاتصال مثل هذا:
$loop->addWriteStream($stream, function ($stream) use ($name) {fwrite($stream, 'Hello' . $name); });
انظر أيضًا المثال رقم 12.
يمكنك استدعاء removeWriteStream()
لإزالة مستمع حدث الكتابة لهذا الدفق.
لا يتم ضمان ترتيب تنفيذ المستمعين عندما تصبح التدفقات المتعددة جاهزة في نفس الوقت.
يمكن استخدام الأسلوب removeReadStream(resource $stream): void
لإزالة مستمع حدث القراءة للدفق المحدد.
إن إزالة دفق من الحلقة التي تمت إزالتها بالفعل أو محاولة إزالة دفق لم تتم إضافته مطلقًا أو غير صالح ليس له أي تأثير.
يمكن استخدام الأسلوب removeWriteStream(resource $stream): void
لإزالة مستمع أحداث الكتابة للدفق المحدد.
إن إزالة دفق من الحلقة التي تمت إزالتها بالفعل أو محاولة إزالة دفق لم تتم إضافته مطلقًا أو غير صالح ليس له أي تأثير.
الطريقة الموصى بها لتثبيت هذه المكتبة هي من خلال Composer. جديد للملحن؟
بمجرد إطلاقه، سيتبع هذا المشروع SemVer. في الوقت الحالي، سيؤدي هذا إلى تثبيت أحدث إصدار للتطوير:
يتطلب الملحن رد فعل/حلقة حدث:^3@dev
راجع أيضًا سجل التغيير للحصول على تفاصيل حول ترقيات الإصدار.
يهدف هذا المشروع إلى التشغيل على أي نظام أساسي وبالتالي لا يتطلب أي امتدادات PHP ويدعم التشغيل على PHP 7.1 حتى PHP 8+ الحالي. يوصى بشدة باستخدام أحدث إصدار PHP مدعوم لهذا المشروع.
يُقترح تثبيت أي من ملحقات حلقة الأحداث، ولكنه أمر اختياري تمامًا. راجع أيضًا تطبيقات حلقة الأحداث لمزيد من التفاصيل.
لتشغيل مجموعة الاختبار، تحتاج أولاً إلى استنساخ هذا الريبو ثم تثبيت جميع التبعيات من خلال Composer:
تثبيت الملحن
لتشغيل مجموعة الاختبار، انتقل إلى جذر المشروع وقم بتشغيل:
البائع/بن/phpunit
معهد ماساتشوستس للتكنولوجيا، راجع ملف الترخيص.
راجع مكون التدفق الخاص بنا للحصول على مزيد من المعلومات حول كيفية استخدام التدفقات في تطبيقات العالم الحقيقي.
راجع موقع Wiki الخاص بالمستخدمين والمعالين على Packagist للحصول على قائمة بالحزم التي تستخدم EventLoop في تطبيقات العالم الحقيقي.