PHP几种回调写法

PHP里通过匿名函数写回调是最方便的,但是除了匿名函数方式的回调,PHP还有其它的回调写法。以下是PHP几种回调写法的示例。

1、匿名函数回调

  1. <?php
  2. use Workerman\Worker;
  3. use Workerman\Connection\TcpConnection;
  4. use Workerman\Protocols\Http\Request;
  5. require_once __DIR__ . '/vendor/autoload.php';
  6. $http_worker = new Worker("http://0.0.0.0:2345");
  7. // 匿名函数回调
  8. $http_worker->onMessage = function(TcpConnection $connection, Request $data)
  9. {
  10. // 向浏览器发送hello world
  11. $connection->send('hello world');
  12. };
  13. Worker::runAll();

2、普通函数回调

  1. <?php
  2. use Workerman\Worker;
  3. use Workerman\Connection\TcpConnection;
  4. use Workerman\Protocols\Http\Request;
  5. require_once __DIR__ . '/vendor/autoload.php';
  6. $http_worker = new Worker("http://0.0.0.0:2345");
  7. // 匿名函数回调
  8. $http_worker->onMessage = 'on_message';
  9. // 普通函数
  10. function on_message(TcpConnection $connection, Request $request)
  11. {
  12. // 向浏览器发送hello world
  13. $connection->send('hello world');
  14. }
  15. Worker::runAll();

3、类方法作为回调

MyClass.php

  1. use Workerman\Worker;
  2. use Workerman\Connection\TcpConnection;
  3. class MyClass{
  4. public function __construct(){}
  5. public function onWorkerStart(Worker $worker){}
  6. public function onConnect(TcpConnection $connection){}
  7. public function onMessage(TcpConnection $connection, $message) {}
  8. public function onClose(TcpConnection $connection){}
  9. public function onWorkerStop(TcpConnection $connection){}
  10. }

启动脚本 start.php

  1. <?php
  2. use Workerman\Worker;
  3. require_once __DIR__ . '/vendor/autoload.php';
  4. // 载入MyClass
  5. require_once __DIR__.'/MyClass.php';
  6. $worker = new Worker("websocket://0.0.0.0:2346");
  7. // 创建一个对象
  8. $my_object = new MyClass();
  9. // 调用类的方法
  10. $worker->onWorkerStart = array($my_object, 'onWorkerStart');
  11. $worker->onConnect = array($my_object, 'onConnect');
  12. $worker->onMessage = array($my_object, 'onMessage');
  13. $worker->onClose = array($my_object, 'onClose');
  14. $worker->onWorkerStop = array($my_object, 'onWorkerStop');
  15. Worker::runAll();

注意: 以上的代码结构不允许在构造函数里初始化资源(MySQL连接、Redis连接、Memcache连接等),因为$my_object = new MyClass();运行在主进程。以MySQL为例,在主进程初始化的MySQL连接等资源会被子进程继承,每个子进程都可以操作这个数据库连接,但是这些连接在MySQL服务端对应的是同一个连接,会发生不可预期的错误,例如mysql gone away 错误。

以上代码结构如果需要在类的构造函数里初始化资源,可以采用以下写法。 MyClass.php

  1. use Workerman\Worker;
  2. use Workerman\Connection\TcpConnection;
  3. class MyClass{
  4. protected $db = null;
  5. public function __construct(){
  6. // 假设数据库连接类是MyDbClass
  7. $db = new MyDbClass();
  8. }
  9. public function onWorkerStart(Worker $worker){}
  10. public function onConnect(TcpConnection $connection){}
  11. public function onMessage(TcpConnection $connection, $message) {}
  12. public function onClose(TcpConnection $connection){}
  13. public function onWorkerStop(TcpConnection $connection){}
  14. }

启动脚本 start.php

  1. <?php
  2. use Workerman\Worker;
  3. require_once __DIR__ . '/vendor/autoload.php';
  4. $worker = new Worker("websocket://0.0.0.0:2346");
  5. // 在onWorkerStart里初始化类
  6. $worker->onWorkerStart = function($worker) {
  7. // 载入MyClass
  8. require_once __DIR__.'/MyClass.php';
  9. // 创建一个对象
  10. $my_object = new MyClass();
  11. // 调用类的方法
  12. $worker->onConnect = array($my_object, 'onConnect');
  13. $worker->onMessage = array($my_object, 'onMessage');
  14. $worker->onClose = array($my_object, 'onClose');
  15. $worker->onWorkerStop = array($my_object, 'onWorkerStop');
  16. };
  17. Worker::runAll();

上面代码结构中onWorkerStart运行时已经是属于子进程,等于每个子进程各自建立自己的MySQL连接,所以不会有共享连接的问题。 这样还有一个好处就是支持业务代码reload。由于MyClass.php是在子进程载入的,根据reload规则业务更改MyClass.php后直接reload即可生效。

4、类的静态方法作为回调

静态类MyClass.php

  1. use Workerman\Worker;
  2. use Workerman\Connection\TcpConnection;
  3. class MyClass{
  4. public static function onWorkerStart(Worker $worker){}
  5. public static function onConnect(TcpConnection $connection){}
  6. public static function onMessage(TcpConnection $connection, $message) {}
  7. public static function onClose(TcpConnection $connection){}
  8. public static function onWorkerStop(TcpConnection $connection){}
  9. }

启动脚本 start.php

  1. <?php
  2. use Workerman\Worker;
  3. require_once __DIR__ . '/vendor/autoload.php';
  4. // 载入MyClass
  5. require_once __DIR__.'/MyClass.php';
  6. $worker = new Worker("websocket://0.0.0.0:2346");
  7. // 调用类的静态方法。
  8. $worker->onWorkerStart = array('MyClass', 'onWorkerStart');
  9. $worker->onConnect = array('MyClass', 'onConnect');
  10. $worker->onMessage = array('MyClass', 'onMessage');
  11. $worker->onClose = array('MyClass', 'onClose');
  12. $worker->onWorkerStop = array('MyClass', 'onWorkerStop');
  13. // 如果类带命名空间,则是类似这样的写法
  14. // $worker->onWorkerStart = array('your\namesapce\MyClass', 'onWorkerStart');
  15. // $worker->onConnect = array('your\namesapce\MyClass', 'onConnect');
  16. // $worker->onMessage = array('your\namesapce\MyClass', 'onMessage');
  17. // $worker->onClose = array('your\namesapce\MyClass', 'onClose');
  18. // $worker->onWorkerStop = array('your\namesapce\MyClass', 'onWorkerStop');
  19. Worker::runAll();

注意:根据PHP的运行机制,如果没用调用new 则不会调用构造函数,另外静态类的方法里面不允许使用$this