Varias maneras de escribir callbacks en PHP
Usar funciones anónimas para escribir callbacks en PHP es lo más conveniente, pero además de este método, PHP tiene otras maneras de escribir callbacks. A continuación se presentan algunos ejemplos de distintas formas de callbacks en PHP.
1. Callback con función 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 con función anónima
$http_worker->onMessage = function(TcpConnection $connection, Request $data)
{
// Enviar 'hello world' al navegador
$connection->send('hello world');
};
Worker::runAll();
2. Callback con función normal
<?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 con función normal
$http_worker->onMessage = 'on_message';
// Función normal
function on_message(TcpConnection $connection, Request $request)
{
// Enviar 'hello world' al navegador
$connection->send('hello world');
}
Worker::runAll();
3. Método de clase 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 inicio start.php
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// Cargar MyClass
require_once __DIR__.'/MyClass.php';
$worker = new Worker("websocket://0.0.0.0:2346");
// Crear un objeto
$my_object = new MyClass();
// Llamar a los métodos de la clase
$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();
Nota:
La estructura de código anterior no permite inicializar recursos en el constructor (conexiones MySQL, conexiones Redis, conexiones Memcache, etc.), porque $my_object = new MyClass(); se ejecuta en el proceso principal. Tomando MySQL como ejemplo, los recursos como la conexión MySQL inicializados en el proceso principal serán heredados por los procesos secundarios, lo que significa que cada proceso secundario podrá operar con esta conexión a la base de datos, pero en el servidor MySQL, estas conexiones corresponden a la misma conexión, lo que puede causar errores inesperados, como el error mysql gone away.
Si se necesita inicializar recursos en el constructor de la clase con la estructura de código anterior, se puede usar la siguiente forma.
MyClass.php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
class MyClass{
protected $db = null;
public function __construct(){
// Supongamos que la clase de conexión a la base de datos es MyDbClass
$this->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 inicio start.php
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker("websocket://0.0.0.0:2346");
// Inicializar la clase en onWorkerStart
$worker->onWorkerStart = function($worker) {
// Cargar MyClass
require_once __DIR__.'/MyClass.php';
// Crear un objeto
$my_object = new MyClass();
// Llamar a los métodos de la clase
$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();
En la estructura anterior, onWorkerStart se ejecuta ya en el proceso secundario, lo que significa que cada proceso secundario establece su propia conexión MySQL, evitando así problemas de conexión compartida.
Además, esto tiene la ventaja de soportar la recarga del código de negocio. Dado que MyClass.php se carga en el proceso secundario, según las reglas de recarga, si se modifica MyClass.php, simplemente se puede recargar para que surta efecto.
4. Método estático de clase como callback
Clase 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 inicio start.php
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// Cargar MyClass
require_once __DIR__.'/MyClass.php';
$worker = new Worker("websocket://0.0.0.0:2346");
// Llamar a los métodos estáticos de la clase.
$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');
// Si la clase tiene un espacio de nombres, se hace algo así
// $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();
Nota:
Según el mecanismo de funcionamiento de PHP, si no se llama a new, no se ejecutará el constructor. Además, no se permite el uso de $this dentro de métodos de una clase estática.