PHP Callback-Methoden

In PHP ist es am bequemsten, Rückrufe über anonyme Funktionen zu schreiben, aber neben der anonyme Funktionsweise gibt es auch andere Callback-Methoden in PHP. Hier sind einige Beispiele für Callback-Methoden in PHP.

1. Anonyme Funktionsrückrufe

<?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");

// Anonyme Funktionsrückrufe
$http_worker->onMessage = function(TcpConnection $connection, Request $data)
{
    // Sendet hello world an den Browser
    $connection->send('hello world');
};

Worker::runAll();

2. Normale Funktionsrückrufe

<?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");

// Normale Funktionsrückrufe
$http_worker->onMessage = 'on_message';

// Normale Funktion
function on_message(TcpConnection $connection, Request $request)
{
    // Sendet hello world an den Browser
    $connection->send('hello world');
}

Worker::runAll();

3. Klassenmethoden als Rückrufe

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){}
}

Startskript start.php

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

// Ladet MyClass
require_once __DIR__.'/MyClass.php';

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

// Erstellt ein Objekt
$my_object = new MyClass();

// Ruft die Methoden der Klasse auf
$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();

Hinweis:
Die obige Code-Struktur erlaubt es nicht, Ressourcen (MySQL-Verbindung, Redis-Verbindung, Memcache-Verbindung usw.) im Konstruktor zu initialisieren, da $my_object = new MyClass(); im Hauptprozess ausgeführt wird. Um ein Beispiel für MySQL zu nehmen: In dem Hauptprozess initialisierte MySQL-Verbindungen und ähnliche Ressourcen werden von den Unterprozessen geerbt, jeder Unterprozess kann diese Datenbankverbindung verwenden, aber diese Verbindungen entsprechen auf der MySQL-Server-Seite derselben Verbindung, was zu unvorhersehbaren Fehlern führen kann, wie z.B. mysql gone away-Fehler.

Wenn die obige Code-Struktur Ressourcen im Konstruktor der Klasse initialisieren muss, kann der folgende Ansatz verwendet werden.
MyClass.php

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
class MyClass{
    protected $db = null;
    public function __construct(){
        // Angenommen, die Datenbankverbindungsklasse ist 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){}
}

Startskript start.php

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

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

// Initialisiert die Klasse in onWorkerStart
$worker->onWorkerStart = function($worker) {
    // Ladet MyClass
    require_once __DIR__.'/MyClass.php';

    // Erstellt ein Objekt
    $my_object = new MyClass();

    // Ruft die Methoden der Klasse auf
    $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();

In der obigen Code-Struktur wird onWorkerStart bereits im子prozess ausgeführt, was bedeutet, dass jeder Unterprozess seine eigene MySQL-Verbindung aufbaut, sodass keine gemeinsamen Verbindungsprobleme auftreten.
Ein weiterer Vorteil ist, dass Geschäftscode neu geladen werden kann. Da MyClass.php im Unterprozess geladen wird, kann eine Änderung an MyClass.php gemäß den Neulade-Regeln direkt neu geladen werden und wirksam werden.

4. Statische Methoden der Klasse als Rückrufe

Statische Klasse 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){}
}

Startskript start.php

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

// Ladet MyClass
require_once __DIR__.'/MyClass.php';

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

// Ruft die statischen Methoden der Klasse auf.
$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');

// Wenn die Klasse einen Namensraum hat, wäre die Schreibweise ähnlich wie folgt
// $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();

Hinweis:
Nach der Ausführungsmechanik von PHP wird der Konstruktor nicht aufgerufen, wenn new nicht verwendet wird, und außerdem darf innerhalb statischer Klassmethoden kein $this verwendet werden.