วิธีการเรียกกลับใน 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 ระบบย่อยก็จะโหลดเพียงอย่างเดียวซึ่งทำให้มากคือมันสามารถใช้งานได้ทันที

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 ภายในโค้ด