عدة طرق لاستدعاء دوال في PHP

في PHP، يعتبر استخدام دوال مجهولة الكتابة كنداء للدوال الأسهل، ولكن بخلاف طريقة الاستدعاء باستخدام دوال مجهولة الكتابة، هناك طرق أخرى لاستدعاء الدوال في PHP. فيما يلي بعض الأمثلة على طرق الاستدعاء في PHP.

1. استدعاء باستخدام دوال مجهولة الكتابة

<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';

$http_worker = new Worker("http://0.0.0.0:2345");

// استدعاء باستخدام دالة مجهولة الكتابة
$http_worker->onMessage = function(TcpConnection $connection, Request $data)
{
    // إرسال hello world إلى المتصفح
    $connection->send('hello world');
};

Worker::runAll();

2. استدعاء باستخدام دالة عادية

<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
require_once __DIR__ . '/vendor/autoload.php';

$http_worker = new Worker("http://0.0.0.0:2345");

// استدعاء باستخدام دالة عادية
$http_worker->onMessage = 'on_message';

// دالة عادية
function on_message(TcpConnection $connection, Request $request)
{
    // إرسال hello world إلى المتصفح
    $connection->send('hello world');
}

Worker::runAll();

3. استخدام طرق الأصناف كنداءات

MyClass.php

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
class MyClass{
    public function __construct(){}
    public function onWorkerStart(Worker $worker){}
    public function onConnect(TcpConnection $connection){}
    public function onMessage(TcpConnection $connection, $message) {}
    public function onClose(TcpConnection $connection){}
    public function onWorkerStop(Worker $worker){}
}

السكربت الانطلاق start.php

<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';

// تحميل MyClass
require_once __DIR__.'/MyClass.php';

$worker = new Worker("websocket://0.0.0.0:2346");

// إنشاء كائن
$my_object = new MyClass();

// استدعاء طرق الصنف
$worker->onWorkerStart = array($my_object, 'onWorkerStart');
$worker->onConnect     = array($my_object, 'onConnect');
$worker->onMessage     = array($my_object, 'onMessage');
$worker->onClose       = array($my_object, 'onClose');
$worker->onWorkerStop  = array($my_object, 'onWorkerStop');

Worker::runAll();

ملاحظة:
هيكلية الكود أعلاه لا تسمح بتهيئة الموارد (مثل اتصال MySQL أو Redis أو Memcache) في الدالة المنشئة، لأن $my_object = new MyClass(); يعمل في العملية الرئيسية. على سبيل المثال، في عملية تهيئة اتصال MySQL في العملية الرئيسية، ستقوم العمليات الفرعية بتحمل هذه الموارد، مما يعني أن كل عملية فرعية يمكنها التحكم في اتصال قاعدة البيانات، ولكن هذه الاتصالات من جهة خدمة MySQL ستكون نفس الاتصال، مما يؤدي إلى أخطاء غير متوقعة، مثل خطأ mysql gone away.

إذا كان من الضروري تهيئة الموارد في دالة المنشئ، يمكن استخدام الكود التالي.
MyClass.php

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
class MyClass{
    protected $db = null;
    public function __construct(){
        // افترض أن فئة الاتصال بقاعدة البيانات هي MyDbClass
        $db = new MyDbClass();
    }
    public function onWorkerStart(Worker $worker){}
    public function onConnect(TcpConnection $connection){}
    public function onMessage(TcpConnection $connection, $message) {}
    public function onClose(TcpConnection $connection){}
    public function onWorkerStop(Worker $worker){}
}

السكربت الانطلاق start.php

<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker("websocket://0.0.0.0:2346");

// تهيئة الصنف في onWorkerStart
$worker->onWorkerStart = function($worker) {
    // تحميل MyClass
    require_once __DIR__.'/MyClass.php';

    // إنشاء كائن
    $my_object = new MyClass();

    // استدعاء طرق الصنف
    $worker->onConnect    = array($my_object, 'onConnect');
    $worker->onMessage    = array($my_object, 'onMessage');
    $worker->onClose      = array($my_object, 'onClose');
    $worker->onWorkerStop = array($my_object, 'onWorkerStop');
};

Worker::runAll();

في هيكلية الكود أعلاه، يتم تشغيل onWorkerStart في كل عملية فرعية، مما يعني أن كل عملية فرعية تقوم بإنشاء اتصال MySQL خاص بها، وبالتالي لا توجد مشكلة في الاتصالات المشتركة.
تتمثل فائدة أخرى في دعم إعادة تحميل كود الأعمال. حيث إن MyClass.php يتم تحميله في العمليات الفرعية، وفقًا لقواعد إعادة التحميل، سيسري أي تغيير على MyClass.php مباشرة بعد إعادة التحميل.

4. استخدام الطرق الثابتة كنداءات

MyClass.php الثابتة

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
class MyClass{
    public static function onWorkerStart(Worker $worker){}
    public static function onConnect(TcpConnection $connection){}
    public static function onMessage(TcpConnection $connection, $message) {}
    public static function onClose(TcpConnection $connection){}
    public static function onWorkerStop(Worker $worker){}
}

السكربت الانطلاق start.php

<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';

// تحميل MyClass
require_once __DIR__.'/MyClass.php';

$worker = new Worker("websocket://0.0.0.0:2346");

// استدعاء الطرق الثابتة للصنف.
$worker->onWorkerStart = array('MyClass', 'onWorkerStart');
$worker->onConnect     = array('MyClass', 'onConnect');
$worker->onMessage     = array('MyClass', 'onMessage');
$worker->onClose       = array('MyClass', 'onClose');
$worker->onWorkerStop  = array('MyClass', 'onWorkerStop');

// إذا كان للصنف مساحة اسم، فسيكون ذلك بطريقة مشابهة لتلك
// $worker->onWorkerStart = array('your\namesapce\MyClass', 'onWorkerStart');
// $worker->onConnect     = array('your\namesapce\MyClass', 'onConnect');
// $worker->onMessage     = array('your\namesapce\MyClass', 'onMessage');
// $worker->onClose       = array('your\namesapce\MyClass', 'onClose');
// $worker->onWorkerStop  = array('your\namesapce\MyClass', 'onWorkerStop');

Worker::runAll();

ملاحظة: وفقًا لآلية تشغيل PHP، إذا لم يتم استدعاء new فلن يتم استدعاء الدالة المنشئة، بالإضافة إلى أن الطرق الثابتة للصنف لا يمكنها استخدام $this.