الحقيقة حول PHP غير المتزامن (Async PHP): الـ Fibers، وepoll، وPHP 8.6

عملتُ مع Laravel لسنوات. كنت أستخدم PHP المتزامن (sync PHP). يأتي الطلب، تعمل العملية، ثم يُرسل الرد. لم أكن بحاجة أبداً إلى كود غير متزامن (async code).

ثم قرأت عن واجهة برمجة تطبيقات الاستطلاع (Polling API) الجديدة في PHP 8.6. لقد غير ذلك نظرتي لكل شيء.

إليكم ما تعلمته حول كيفية عمل الـ async "تحت الغطاء" (under the hood).

مشكلة الإدخال والإخراج (IO Problem)

عندما تستدعي واجهة برمجة تطبيقات (API)، تنتظر عملية PHP الخاصة بك. مثال: $response = Http::get('https://api.example.com');

إذا استغرقت هذه الاستدعاء 300 مللي ثانية، فلن يفعل المعالج (CPU) أي شيء لمدة 300 مللي ثانية. سيبقى في حالة خمول. هذا ما يسمى بـ "الإدخال والإخراج المعطل" (blocking I/O).

إذا كان لديك ثلاثة استدعاءات لـ API:

  • API A: 300ms
  • API B: 400ms
  • API C: 200ms

المجموع المتسلسل: 900ms. المجموع غير المتزامن (Async): 400ms (وقت أبطأ استدعاء).

يسمح الـ Async لعمليتك بالقيام بأعمال أخرى أثناء انتظار البيانات.

Select مقابل epoll

للقيام بالـ async، تحتاج إلى معرفة أي socket لديه بيانات جاهزة.

1. select()

استخدمت PHP دالة stream_select() منذ الإصدار 4. وهي تعمل من خلال طلب من النواة (kernel) مراقبة قائمة من الـ sockets. المشكلة: في كل مرة تصل فيها البيانات، يجب عليك فحص القائمة بأكملها مرة أخرى. هذه هي "ضريبة إعادة الفحص" (rescan tax). كما أن لها حداً أقصى يبلغ حوالي 1024 اتصالاً.

2. epoll (Linux) / kqueue (macOS)

هذه ميزات في النواة (kernel). بدلاً من فحص قائمة، تحتفظ النواة بـ "قائمة جاهزة" (ready-list). وهي تخبرك فقط بالـ sockets المحددة الجاهزة. هذا يسمح بالتوسع إلى آلاف الاتصالات دون عمل إضافي.

الـ epoll ليست ميزة في PHP، بل هي ميزة في Linux. وتستخدمها لغات مثل Go و Rust و Node.js جميعاً.

Fibers: زر الإيقاف المؤقت

قدم PHP 8.1 الـ Fibers. كنت أعتقد أن الـ Fibers ستستيقظ من تلقاء نفسها، لكنها لا تفعل ذلك.

الـ Fiber يشبه فيديو متوقف مؤقتاً. يظل متوقفاً حتى يقوم شخص ما باستدعاء $fiber->resume().

حلقة الأحداث (Event Loop) هي مجرد جزء من كود PHP يقرر متى يستدعي resume().

يتطلب الـ Async I/O ثلاثة أجزاء:

  • الإيقاف (Pause): الـ Fibers (نواة PHP 8.1)
  • القرار (Decide): حلقة الأحداث (Event Loop) (كود PHP بسيط)
  • المعرفة (Know): استطلاع النواة (Kernel Polling) (epoll/kqueue)

قبل PHP 8.6، كان لدى PHP جزأا "الإيقاف" و"القرار"، ولكن جزء "المعرفة" كان يعتمد على select() القديمة أو إضافات C (C extensions) البطيئة.

يسد PHP 8.6 هذه الفجوة، حيث يجلب واجهة برمجة تطبيقات استطلاع (Polling API) أصلية إلى النواة. الآن، يمكن لـ PHP استخدام epoll أو kqueue مباشرة دون الحاجة إلى إضافات خارجية.

الخلاصة

إذا كنت تستخدم Laravel مع PHP-FPM، فلن تحتاج إلى تغيير أي شيء اليوم.

ولكن افهم هذا: الـ Async ليس سحراً، بل هو مجرد طريقة ذكية لإدارة وقت الانتظار.

توقف عن مجرد استهلاك الكود. قم بتشغيل سكربت بسيط. قم بإفساده. هذه هي الطريقة التي تتعلم بها حقاً.

المصدر: https://dev.to/alamriku/sync-php-developer-hisebe-async-php-bujhte-giye-yaa-shikhlaam-fibers-epoll-aar-php-86-462j