Várias maneiras de callback em PHP
A maneira mais conveniente de escrever callbacks em PHP é através de funções anônimas, mas além do método de funções anônimas, PHP também possui outras maneiras de implementar callbacks. Abaixo estão exemplos de várias maneiras de callbacks em PHP.
1. Callback de função anônima
<?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");
// Callback de função anônima
$http_worker->onMessage = function(TcpConnection $connection, Request $data)
{
// Envia "hello world" para o navegador
$connection->send('hello world');
};
Worker::runAll();
2. Callback de função comum
<?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");
// Callback de função anônima
$http_worker->onMessage = 'on_message';
// Função comum
function on_message(TcpConnection $connection, Request $request)
{
// Envia "hello world" para o navegador
$connection->send('hello world');
}
Worker::runAll();
3. Método de classe como callback
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){}
}
Script de inicialização start.php
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// Carrega MyClass
require_once __DIR__.'/MyClass.php';
$worker = new Worker("websocket://0.0.0.0:2346");
// Cria um objeto
$my_object = new MyClass();
// Chama os métodos da classe
$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();
Atenção:
A estrutura acima do código não permite que recursos (conexões MySQL, conexões Redis, conexões Memcache, etc.) sejam inicializados no construtor, porque $my_object = new MyClass(); é executado no processo principal. Por exemplo, se uma conexão MySQL for inicializada no processo principal, este recurso será herdado pelos subprocessos, e cada subprocesso poderá operar essa conexão de banco de dados, mas essas conexões no servidor MySQL corresponderão à mesma conexão, o que pode causar erros imprevistos, como o erro mysql gone away.
Se a estrutura de código acima precisar inicializar recursos no construtor da classe, pode-se usar a seguinte abordagem.
MyClass.php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
class MyClass{
protected $db = null;
public function __construct(){
// Supondo que a classe de conexão ao banco de dados é 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){}
}
Script de inicialização start.php
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker("websocket://0.0.0.0:2346");
// Inicializa a classe em onWorkerStart
$worker->onWorkerStart = function($worker) {
// Carrega MyClass
require_once __DIR__.'/MyClass.php';
// Cria um objeto
$my_object = new MyClass();
// Chama os métodos da classe
$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();
Na estrutura de código acima, onWorkerStart é executado no subprocesso, o que significa que cada subprocesso estabelece sua própria conexão MySQL, portanto, não há problemas de conexão compartilhada.
Outra vantagem é que suporta recarregar o código de negócios. Como MyClass.php é carregado no subprocesso, após modificar MyClass.php, é possível recarregar e as alterações entrarão em vigor imediatamente.
4. Método estático de classe como callback
Classe estática 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){}
}
Script de inicialização start.php
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// Carrega MyClass
require_once __DIR__.'/MyClass.php';
$worker = new Worker("websocket://0.0.0.0:2346");
// Chama os métodos estáticos da classe.
$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');
// Se a classe tiver namespaces, a escrita deve ser semelhante a:
// $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();
Atenção: De acordo com o mecanismo de execução do PHP, se não for usado o comando new, o construtor não será chamado, além disso, métodos de classes estáticas não podem usar $this.