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接続を確立することになり、接続の共有問題は発生しません。また、これはビジネスコードのreloadをサポートするという利点もあります。なぜならMyClass.phpが子プロセスでロードされるため、reloadの規則に従ってMyClass.phpに加えた変更を直接reloadすることで反映させることができます。
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を使用することはできません。