## ** Swoole新手包开发手册 **
[TOC]
#### **前言**
Swoole新手包(以下简称新手包)虽名为新手包,但本意是倡导低代码情况下完成进阶开发,最大限度降低学习成本,掌握核心技术。新手包对Swoole进行高度封装,对于之前没有或较少接触过多进程、协程、多种通信协议模块等技术实现的开发者使其快速掌握进阶开发,可以在任何PHP框架或原生PHP中进行开发,完美兼容。
#### **部署新手包**
------
##### 环境要求
- 保证**php**版本>=**7.0**
- 保证**关系型数据库**采用**Mysql**
- 保证**缓存数据库**采用**Redis**
- 保证**Swoole**扩展版本>= **4.6.7**同时<**5.0**
##### 下载部署
1、通过以下几种方式下载新手包:
- [https://www.easylt.cn](https://www.easylt.cn)官网直接下载,在技术支持-新手包系列中选择Swoole新手包进入并下载。
- Git下载指令:git clone https://github.com/myframe1002223338/swoole-novice.git
- composer安装指令:composer create-project "swoole-novice/swoole-novice":"dev-master"
PS:composer安装显示以下错误:
[Symfony\Component\Process\Exception\RuntimeException]
The Process class relies on proc_open, which is not available on your PHP installation.
解决方法:打开php.ini,搜索disable_functions,找到disable_functions = xxx,xxx,xxx...删除其中的
proc_open保存并重启服务器即可。
2、将下载的Swoole新手包复制到项目任意目录下即可。
#### **使用新手包**
------
##### 配置文件
- 请在新手包根目录打开src/config目录,在config_db.php中对数据库连接常量进行相应的配置更改。
- config_swoole.php是Swoole配置文件,默认无需配置更改;请打开查看每一项配置说明便于后期进行特殊化配置。
##### 引入依赖
使用新手包开发需引入依赖,autoload.php为加载文件,在项目中引入该文件即可;如Swoole新手包放置到项目根目录下,此时在项目根目录下创建test.php并在文件顶部require('swoole-novice/autoload.php');
**PS:require('')中的路径根据实际项目目录结构调整**
##### **创建服务**
###### 运行模式
除TCP、UDP、HTTP、WebSocket、RPC的客户端可以选择通过WEB服务器(FPM)运行,且WebSocket客户端仅支持WEB服务器(FPM)运行,其他必须通过CLI模式运行。
**PS:服务器、客户端中不可创建容器,如多进程、协程/异步Mysql/Redis容器,但多进程容器中可以包含服务器、客户端、协程/异步Mysql/Redis容器。**
###### DB操作
- **通过CLI模式运行新手包创建的服务支持异步Mysql、异步Redis、同步Mysql、同步Redis的DB操作;服务器中的TASK异步任务仅支持同步Mysql、同步Redis。**
- **通过WEB服务器运行新手包创建的TCP、UDP、HTTP、WebSocket、RPC客户端仅支持同步Mysql、同步Redis。**
- **异步Mysql、异步Redis、同步Mysql、同步Redis具体操作请阅读以下相关文档。**
###### TCP服务器
- 创建服务器【必须实现】
$tcp_serv = new Tcp_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Tcp_server('',9501);**
- 当客户端连接成功时触发【可选项】
$tcp_serv->connect(function(){
//匿名回调函数中写你的业务
});
- 当接收到请求数据时【必须实现】
$tcp_serv->receive(function($request_data){
//$request_data为客户端发送的数据
//匿名回调函数中写你的业务
//如需给客户端返回数据请return $var
});
- 处理task异步任务,具体操作请阅读**异步任务**部分文档【可选项】
$tcp_serv->task(function($request_data,$task_id,$reactor_id){
//$request_data为客户端发送的数据
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- task异步任务完成事件【如启用task则必须实现】
$tcp_serv->finish(function($state,$task_id,$reactor_id){
//$state为task异步任务运行结果状态,当$state等于true时,异步任务运行完成。
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- 当客户端关闭成功时触发【可选项】
$tcp_serv->close(function(){
//匿名回调函数中写你的业务
});
- 启动服务器【必须实现】
$tcp_serv->start();
###### TCP客户端
- 创建客户端【必须实现】
$tcp_cli = new Tcp_client($ip,$port);
//$ip为服务器ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Tcp_client('',9501);**
- 像服务器发送数据【必须实现】
$tcp_cli->send(function(){
//匿名回调函数中写你的业务
//如需发送数据请return $var
});
- 从服务器接收数据【必须实现】
$tcp_cli->receive(function($response_data){
//$response_data为服务器返回的数据
//匿名回调函数中写你的业务
});
- 关闭连接【必须实现】
$tcp_cli->close();
###### UDP服务器
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建服务器【必须实现】
$udp_serv = new Udp_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Udp_server('',9501);**
- 当接收到请求数据时【必须实现】
$udp_serv->receive(function($request_data){
//$request_data为客户端发送的数据
//匿名回调函数中写你的业务
//如需给客户端返回数据请return $var
});
- 处理task异步任务,具体操作请阅读**异步任务**部分文档【可选项】
$udp_serv->task(function($request_data,$task_id,$reactor_id){
//$request_data为客户端发送的数据
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- task异步任务完成事件【如启用task则必须实现】
$udp_serv->finish(func
###### UDP客户端
- 创建客户端【必须实现】
$udp_cli = new Udp_client($ip,$port);
//$ip为服务器ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Udp_client('',9501);**
- 像服务器发送数据【必须实现】
$udp_cli->send(function(){
//匿名回调函数中写你的业务
//如需发送数据请return $var
});
- 从服务器接收数据【必须实现】
$udp_cli->receive(function($response_data){
//$response_data为服务器返回的数据
//匿名回调函数中写你的业务
});
###### HTTP服务器
- 创建服务器【必须实现】
$http_serv = new Http_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Http_server('',9501);**
- 当接收到请求数据时【必须实现】
$http_serv->receive(function($request_post,$request_get,$headers_message){
//$request_post为客户端发送的post请求数据,$request_get为客户端发送的get请求数据;
//$headers_message为获取头信息请求参数
//匿名回调函数中写你的业务
//如需给客户端返回数据请return $var
});
- 处理task异步任务,具体操作请阅读**异步任务**部分文档【可选项】
$http_serv->task(function($request_post,$request_get,$task_id,$reactor_id){
//$request_post为客户端发送的post请求数据,$request_get为客户端发送的get请求数据;
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- task异步任务完成事件【如启用task则必须实现】
$http_serv->finish(function($state,$task_id,$reactor_id){
//$state为task异步任务运行结果状态,当$state等于true时,异步任务运行完成。
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- 启动服务器【必须实现】
$http_serv->start();
###### HTTP客户端
- 创建客户端【必须实现】
$http_cli = new Http_client($ip,$port);
//$ip为服务器ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Http_client('',9501);**
- 像服务器发送数据并接收服务器返回数据【必须实现】
$result = $http_cli->post(['username'=>'easylt'],$headers);
//发送post请求,如无POST请求数据,请传入空数组[]即可。请求的URL请在config_swoole.php中配置;
//$headers为头信息请求参数,选填项,数据类型必须为array,且为一维数组,元素值用冒号分隔键值对,
如:['Authorization:init']
//$result为服务器返回数据
$result = $http_cli->get('?username=easylt',$headers);
//发送get请求,如无GET请求数据,请传入空字符串''即可。请求的URL请在config_swoole.php中配置,这里
仅跟URI参数,如:?username=easylt&work=frame
//$headers为头信息请求参数,选填项,数据类型必须为array,且为一维数组,元素值用冒号分隔键值对,
如:['Authorization:init']
//$result为服务器返回数据
###### WebSocket服务器
- 创建服务器【必须实现】
$websocket_serv = new Websocket_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Websocket_server('',9501);**
- 当客户端连接成功时触发【可选项】
$websocket_serv->connect(function($request_data,$fd){
//$request_data为客户端发送的数据
//$fd为客户端ID
//匿名回调函数中写你的业务
//如需给客户端返回数据请return $var
});
- 当接收到请求数据时【必须实现】
$websocket_serv->receive(function($request_data,$fd){
//$request_data为客户端发送的数据
**PS:开发一对一发送消息业务时,客户端连接成功时服务器端将userid与socket-fd进行关联缓存到Redis,每次发送数据通过服务器端查询对方的fd并组装对象字符串JSON.stringify({fd:fd})发送给服务器,如果不发送fd则默认fd为自己;**
//$fd为客户端ID
//匿名回调函数中写你的业务
//如需给客户端返回数据请return $var
**//$websocket_serv->receive(function(){});的方法体中可实现一对一(单聊),一对多(群聊)业务,请在config_swoole.php中配置,默认为单聊模式。**
});
- 处理task异步任务,具体操作请阅读**异步任务**部分文档【可选项】
$websocket_serv->task(function($request_data,$task_id,$reactor_id){
//$request_data为客户端发送的数据
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- task异步任务完成事件【如启用task则必须实现】
$websocket_serv->finish(function($state,$task_id,$reactor_id){
//$state为task异步任务运行结果状态,当$state等于true时,异步任务运行完成。
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- 当客户端关闭成功时触发【可选项】
$websocket_serv->close(function($fd){
//$fd为客户端ID
//匿名回调函数中写你的业务
});
- 启动服务器【必须实现】
$websocket_serv->start();
###### WebSocket客户端
- WebSocket客户端请参考官方文档:[https://www.easylt.cn/?href=document3-11](https://www.easylt.cn/?href=document3-11)
###### RPC服务器
远程过程调用,较RESTful风格API接口效率更高,适用于大型系统、多系统间的业务往来。
- 创建服务器【必须实现】
$rpc_serv = new Rpc_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Rpc_server('',9501);**
- 当客户端连接成功时触发【可选项】
$rpc_serv->connect(function(){
//匿名回调函数中写你的业务
});
- 当接收到请求数据时【必须实现】
$rpc_serv->receive(function($function_name,$function_param){
//$function_name为客户端请求的方法名,数据类型为string;
//$function_param为客户端请求的实参,数据类型为array;
//如客户端RPC调用发送请求数据为'func1(liteng,10)',则$function_name为func1,$function_param[0]为liteng,$function_param[1]为10,数字索引下标取值。
//以下为RPC方法定义默认语法示例,统一采用switch 多分支条件结构 :
switch($function_name){
case 'func1': //定义的方法名供客户端调用,以下为方法体用于实现业务;
$name = $function_param[0];
$old_num = $function_param[1];
$int = intval($old_num);
$num = $int + 20;
$result = $name.'一共有'.$num.'颗糖果';
return $result; //如需返回给客户端数据请return $var
break;
case 'func2': //定义的方法名供客户端调用,以下为方法体用于实现业务;
$name = $function_param[0];
$old_num = $function_param[1];
$int = intval($old_num);
$num = $int + 10;
$result = $name.'一共有'.$num.'颗糖果';
return $result; //如需返回给客户端数据请return $var
break;
default: return '方法调用失败'; //客户端请求不传参的返回值,如需返回给客户端数据请return $var;
}
});
- 处理task异步任务,具体操作请阅读**异步任务**部分文档【可选项】
$rpc_serv->task(function($request_data,$task_id,$reactor_id){
//$request_data为客户端发送的数据
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- task异步任务完成事件【如启用task则必须实现】
$rpc_serv->finish(function($state,$task_id,$reactor_id){
//$state为task异步任务运行结果状态,当$state等于true时,异步任务运行完成。
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- 当客户端关闭成功时触发【可选项】
$rpc_serv->close(function(){
//匿名回调函数中写你的业务
});
- 启动服务器【必须实现】
$rpc_serv->start();
###### RPC客户端
- 创建客户端【必须实现】
$rpc_cli = new Rpc_client($ip,$port);
//$ip为服务器ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
**PS:当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Rpc_client('',9501);**
- 像服务器发送数据【必须实现】
$rpc_cli->send(function(){
//匿名回调函数中写你的业务
//如需发送数据请return $var,发送的请求数据格式为方法调用写法,类型为string,如:'func1(liteng,10)'
});
- 从服务器接收数据【必须实现】
$rpc_cli->receive(function($response_data){
//$response_data为服务器返回的数据
//匿名回调函数中写你的业务
});
- 关闭连接【必须实现】
$rpc_cli->close();
###### 多进程
- 有两种创建模式,分别为单独进程模式与进程池模式:**单独进程模式的进程间通信支持QUEUE消息队列;进程池模式的进程间通信支持PIPE管道。**
**//进程模式通过$process>create()中的第二个参数切换,'single'为单独进程模式,'pool'为进程池模式。**
**单独进程模式:**
- 实例化进程【必须实现】
$process = new Process;//单独进程模式下创建多进程运行为异步非阻塞模式,可在每个进程中创建服务器,进程间用QUEUE消息队列通信。
- 创建进程【必须实现】
$process->create(function($process){**//创建第一个进程**
//$process为进程对象
//匿名回调函数中写你的业务
$process->push(mt_rand(1,9));//写入数据到QUEUE消息队列
},'single'); **//'single'为单独进程模式,'pool'为进程池模式。**
$process->create(function($process){**//创建第二个进程**
$read = $process->pop();//读取消息队列中的数据,多进程消息队列为争抢模式,无法将消息投递给指定
进程,但消息是共享的,可一次性读取出来。
echo $read;
},'single');
**进程池模式:**
**PS:pool进程池模式下请勿在进程中创建如TCP等服务器,进程池模式适用于处理有状态消费业务,如从**
**消息队列中读取消息并消费。需要在进程容器中创建如TCP等服务器请选择single单独进程模式。**
- 实例化进程【必须实现】
$process = new Process;//进程池模式运行为异步非阻塞模式,进程间用PIPE管道通信。
- 创建进程池【必须实现】
$process->create(function($process){
//$process为进程对象
//匿名回调函数中写你的业务
//如需写入数据到PIPE管道请return $var
},'pool');
- 读取PIPE管道中的数据【可选项】
$process->pipe(function($response_data){
//匿名回调函数中写你的业务
//$response_data为读取PIPE管道中的数据
});
###### 协程
new Async(function($channel){
**//通过new Async()创建协程容器,将协程放置到容器的匿名回调函数中自动实现异步。**
**//$channel为协程通信通道变量。**
**PS:**
**1、在new Async()协程容器中创建协程才可自动实现异步,但协程容器不可在服务器中创建,如TCP服务器,**
**会发生冲突导致运行错误。**
**2、未创建协程容器时,在配置文件config_swoole.php中配置常量ASYNC_CO开启异步协程同样使协程自动实**
**现异步。**
**3、以下异步Mysql、异步Redis基于协程开发,用法同理;通过异步Mysql、异步Redis读取的数据需要进行发**
**送时,请先判断该数据是否存在,因为是异步非阻塞运行,后续代码优先执行,可能第一次会发送空数据。**
Async::co(function()use($channel){**//创建协程一,同一协程内为同步阻塞执行**
**//协程通信的消费者应小于等于生产者,否则会发生异常,且消费按顺序读取数据;**
$channel->push('发送数据到管道');//先use闭包引入$channel变量,push发送数据到通道;
sleep(10);
echo '这是协程一';
});
Async::co(function()use($channel){**//创建协程二**
$channel->pop();//先use闭包引入$channel变量,pop从通道读取数据;
echo '这是协程二';
});
});
//以上运行协程一执行要等待10秒,则协程一挂起执行协程二,先后输出:这是协程二 这是协程一
###### 异步 Mysql
- 当在如TCP等服务器、协程(不包含多进程容器)容器中创建异步Mysql时,无需创建异步Mysql容器,直接创建异步Mysql,否则会报错。
- 调用匿名函数外的变量请使用闭包写法(同步Mysql同理),如:
new Async_mysql(function()use($var){Async_mysql::co($mysql_conn,$mysql_orm)use($var){}});
new Async_mysql(function(){**//创建异步Mysql容器**
Async_mysql::co(function($mysql_conn,$mysql_orm){**//创建异步Mysql一**
**//$mysql_conn为mysql的mysqli面向过程连接变量,如下数据库操作示例:**
$sql = "insert into account(username) values('异步Mysql操作一')";
mysqli_query($mysql_conn,$sql);
mysqli_close($mysql_conn);
**//$mysql_orm为mysql的orm操作变量,具体操作请阅读ORM文档。**
},10);**//10代表异步Mysql操作时,为避免发生同一时间片资源争抢而导致部分IO执行失败,设置的**
**IO运行周期时间,以秒为单位,非必填项,可自行设置值;**
**PS:如果不设置IO运行周期时间,也默认自动实现IO异步非阻塞模式。**
Async_mysql::co(function($mysql_conn,$mysql_orm){**//创建异步Mysql二**
$sql = "insert into account(username) values('异步Mysql操作二')";
mysqli_query($mysql_conn,$sql);
mysqli_close($mysql_conn);
},5);
});
//以上异步Mysql运行结果为:数据库5秒后写入'异步Mysql操作二',10秒后写入'异步Mysql操作一'。
###### 异步 Redis
- 当在如TCP等服务器、协程(不包含多进程容器)容器中创建异步Redis时,无需创建异步Redis容器,直接创建异步Redis,否则会报错。
- 调用匿名函数外的变量请使用闭包写法(同步Redis同理),如:
new Async_redis(function()use($var){Async_redis::co($mysql_conn,$mysql_orm)use($var){}});
new Async_redis(function(){**//创建异步Redis容器**
Async_redis::co(function($redis){**//创建异步Redis一**
**//$redis为redis连接变量,如下数据库操作示例:**
$redis->set('async1','异步Redis操作一');
echo $redis->get('async1');
$redis->close();
},10);**//10代表异步Redis操作时,为避免发生同一时间片资源争抢而导致部分IO执行失败,设置的**
**IO运行周期时间,以秒为单位,非必填项,可自行设置值;**
**PS:如果不设置IO运行周期时间,也默认自动实现IO异步非阻塞模式。**
Async_redis::co(function($redis){**//创建异步Redis二**
$redis->set('async2','异步Redis操作二');
echo $redis->get('async2');
$redis->close();
},5);
});
//以上异步Redis运行结果为:数据库5秒后写入读取'异步Redis操作二',10秒后写入读取'异步Redis操作一'。
###### 异步cURL
new Async(function($channel){
**PS:**
**1、在new Async()协程容器中创建协程才可自动实现异步,但协程容器不可在服务器中创建,如TCP服务器,**
**会发生冲突导致运行错误。**
**2、未创建协程容器时,在配置文件config_swoole.php中配置常量ASYNC_CO开启异步协程同样使协程自动实**
**现异步。**
Async::co(function()use($channel){**//创建协程一,同一协程内为同步阻塞执行**
**//实例化POST请求的cURL对象;**
$curl_post = new Curl;
$result = $curl_post->post($url,$data,$headers,$status);
//第一个参数为目标文件的url、第二个参数为发送的数据、第三个参数为头信息请求参数(非必填)、第四
个参数为$data数据转换状态值(非必填),$result为请求返回值。
//$headers的数据类型必须为array,且为一维数组,元素值用冒号分隔键值对,如:['Authorization:init']
//$status参数默认可填值为'json'、'form',当头信息请求包含以下参数时:
['Contenttype:application/json','Accept:application/json'],请填入'json',此时body请求参数自动转换为
json格式;
//当头信息请求包含以下参数时:
['Content-Type:application/x-www-form-urlencoded'],请填入'form',此时body请求参数自动转换为uri
拼接参数,如name=easylt&type=php;
});
Async::co(function()use($channel){**//创建协程二**
**//实例化GET请求的cURL对象;**
$curl_post = new Curl_get;
$result = $curl_get->get($url,$headers),第一个参数为目标文件的url、第二个参数为头信息请求参数(非
必填),$result为请求返回值。
//$headers的数据类型必须为array,且为一维数组,元素值用冒号分隔键值对,如:['Authorization:init']
});
});
###### 异步任务(同步Mysql、同步Redis)
- 以上TCP等服务器可选择性创建TASK异步任务,用于异步非阻塞处理一些耗时的任务,启用时需在配置文件config_swoole.php中相应的服务器配置开启异步任务。
- TASK异步任务中不支持协程、异步Mysql、异步Redis,所以当需要对DB操作时,请选择同步Mysql、同步Redis,以TCP服务器为例:
$tcp_serv = new Tcp_server;
$tcp_serv->receive(function($request_data){
return $request_data;
});
$tcp_serv->task(function($request_data,$task_id,$reactor_id){
//$request_data为客户端发送的数据
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
**//创建同步Mysql**
**PS:当配置文件config_swoole.php中配置常量ASYNC_CO为开启异步协程时,创建同步Mysql必须在容器**
**中,即在如TCP等服务器或协程容器中(不含多进程容器,当放置多进程容器中也需包含服务器或协程容器),**
**否则会发生冲突导致运行错误。**
Sync_mysql::co(function($mysql_conn,$mysql_orm){
**//$mysql_conn为mysql的mysqli面向过程连接变量,如下数据库操作示例:**
$sql = "insert into account(username) values('同步Mysql操作')";
mysqli_query($mysql_conn,$sql);
mysqli_close($mysql_conn);
**//$mysql_orm为mysql的orm操作变量,具体操作请阅读ORM文档。**
});
**//创建同步Redis**
**PS:当配置文件config_swoole.php中配置常量ASYNC_CO为开启异步协程时,创建同步Redis必须在容器中,**
**即在如TCP等服务器或协程容器中(不含多进程容器,当放置多进程容器中也需包含服务器或协程容器),否 **
**则会发生冲突导致运行错误。**
Sync_redis::co(function($redis){
**//$redis为redis连接变量,如下数据库操作示例:**
$redis->set('sync','同步Redis操作');
echo $redis->get('sync');
$redis->close();
});
});
$tcp_serv->finish(function($state,$task_id,$reactor_id){
//$state为task异步任务运行结果状态,当$state等于true时,异步任务运行完成。
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
$tcp_serv->start();
###### 定时任务
- 多个定时任务在TCP等服务器/协程容器中,将异步非阻塞执行。
有两种定时器模式,**循环执行定时器** 与 **单次执行定时器**,如下:
$tcp_serv = new Tcp_server;
$tcp_serv->receive(function($request_data){
**//创建循环执行定时器**
Timer::loop(function(){
$mt_rand = mt_rand(1,9);
if($mt_rand==9){
Timer::clear();**//设置条件手动中止执行定时器**
**PS:也可在Timer::loop()中填入第三个选填参数,自动中止执行定时器。**
}
file_get_contents('https://www.baidu.com');//1000毫秒(1秒)后访问一次百度
},1000,10000);
**//1000为定时器循环周期时间,以毫秒为单位,为必填项,可自行设置;10000为定时器中止执行周期时**
**间,以毫秒为单位,为选填项,可自行设置值。**
**//创建单次执行定时器**
Timer::single(function(){
file_get_contents('https://www.baidu.com');//3000毫秒(3秒)后访问一次百度
},3000);
**//3000为定时器中止执行周期时间,以毫秒为单位,为必填项,可自行设置值。**
return $request_data;
});
$tcp_serv->start();
##### **ORM(MySQL)**
ORM实现了mysql增删改查、事务、悲观锁操作,避免书写有漏洞的sql、优化实体类结构,如防止sql注入,同时让业务易于理解、更改。
###### ORM原生写法
**$mysql_orm->db('sql');** //【必填项】直接在类方法实参中传入原生sql
- insert操作,返回成功写入数据的行数量。
- delete操作,必须在sql中设置where条件。返回成功删除数据的行数量。
- update操作,必须在sql中设置where条件。返回成功更新数据的行数量。
- select操作,返回类型为array,返回数据查询结果。
###### ORM非原生写法
ORM非原生写法操作时,首先选择操作模式,写法为:$mysql_orm->model(''); 形参有四种,分别为:insert、delete、update、select,model(),操作模式后的类方法顺序请按照文档顺序调用。
**PS:有两种写法,可组装或分组,$mysql_orm->model('select')->from('*,user')->query();为组装写法,以下为分组写法:**
$mysql_ob = $mysql_orm->model('select');
$mysql_ob->from('*,user');
$mysql_ob->query();
**insert写入操作**
- **$mysql_ob = $mysql_orm->model('insert');** //【必填项】选择操作模式为写入
- **$mysql_ob->table('username&sex,user');** //【必填项】输入写入的字段与表名,用逗号分隔;多字
段用&分隔。
- **$mysql_ob->values('liteng,nan&leiting,nv');** //【与select()方法二选一必填项】输入字段相应写入的
值,用逗号分隔;如果写入多条数据请用&分隔;如参数为变量,拼接如下:
**$mysql_ob->values($username.','.$sex.'&'.$username2.','.$sex2);**
**$mysql_ob->select('select username,sex from user2 where sex=&$nan&');** //【与values()方法
二选一必填项】直接输入sql查询语句,条件值无论为变量、常量、%%模糊查询、[]正则查询或直接输入
标量都需要包含在&$&中间。
- **$mysql_ob->query();** //【必填项】返回成功写入数据的行数量
**delete删除操作**
- **$mysql_ob = $mysql_orm->model('delete');** //【必填项】选择操作模式为删除
- **$mysql_ob->table('user');** //【必填项】输入表名
- **$mysql_ob->where('username=&$'.$username.'& or sex=&$nan&');** //【必填项】条件值无论为变
量、常量、%%模糊查询、[]正则查询或直接输入标量都需要包含在&$&中间,如:
'username=&$'.$username.'&'或'username=&$liteng&'或'username like &$%李%&'
- **$mysql_ob->query();** //【必填项】返回成功删除数据的行数量
**update更新操作**
- **$mysql_ob = $mysql_orm->model('update');** //【必填项】选择操作模式为更新,可多表更新。
- **$mysql_ob->table('user,user2');** //【必填项】输入表名,多表更新用逗号分隔表名。
- **$mysql_ob->set('user.sex=&$nv&,user2.sex=&$nv&');** //【必填项】输入更新字段与值,值无论为
变量、常量或直接输入标量都需要包含在&$&中间且用逗号分隔每组更新参数。
- **$mysql_ob->where('user.username=&$'.$username.'& and user2.username=&$.$username2**
**.'&');** //【必填项】条件值无论为变量、常量、%%模糊查询 、[]正则查询或直接输入标量都需要包含在
&$&中间,如:
'username=&$'.$username.'&'或'username=&$liteng&'或'username like &$%李%&'
- **$mysql_ob->query();** //【必填项】返回成功更新数据的行数量
**select查询操作**
- **$mysql_ob = $mysql_orm->model('select');** //【必填项】选择操作模式为查询,支持全连接查询(PHP
不支持并行查询,内连接查询、外连接查询请用全连接查询拼接sql串行查询)、子 查询、分组查询、模糊
及正则查询;全连接查询、子查询、模糊及正则查询sql语句直接写在where()方法中。
- **$mysql_ob->from('username&sex,user');** //【必填项】输入字段与表名,用逗号分隔;多字段用&分隔。
- **$mysql_ob->where('username=&$'.$username.'& or sex=&$nan&');** //【选填项】条件值无论为变
量、常量、%%模糊查询、[]正则查询或直接输入标量都需要包含在&$&中间,如:
'username=&$'.$username.'&'或'username=&$liteng&'或'username like &$%李%&'
- **$mysql_ob->group_by('username');** //【选填项】输入分组字段名,from()、order_by()方法中字段要和
group_by()中的字段相同,且from()方法中字段格式如下:
'username as 姓名&count(product) as 购物次数,user'
- **$mysql_ob->order_by('username,desc');** //【选填项】输入排序字段名及排序规则-desc\asc,用逗号分
隔。
- **$mysql_ob->limit('0,10');** //【选填项】输入限制结果集参数-offset,num,用逗号分隔,仅输入一个参数
则默认为num。
- **$mysql_ob->query();** //【必填项】返回类型为array,返回数据查询结果。
###### 事务
事务支持ORM的原生、非原生写法,开启事务后必须commit提交或rollback回滚才能结束事务。
- 开启事务:$mysql_orm->trans();
- 事务回滚:$mysql_orm->rollback();
- 事务提交:$mysql_orm->commit();
示例:
$mysql_orm->trans();
$result = $mysql_orm->db("insert into account(username) values('init')");
$result2 = $mysql_orm->db("insert into account(username) values('init2')");
if(!$result || !$result2){
$mysql_orm->rollback();
}
$mysql_orm->commit();
//如上示例,当$result、$result2有一个未执行成功则数据回滚不进行提交。
###### 悲观锁
ORM原生写法的悲观锁请用原生sql自行实现,如select * from account where id=1 for update;
此处仅支持ORM非原生写法且必须开启事务。
- 共享锁(其他事务可以读但不能写),如下:
$mysql_orm->model('select')->from('*,account')->where('id=&$1&')->lock('read')->query();
- 排他锁(其他事务不能读也不能写),如下:
$mysql_orm->model('select')->from('*,account')->where('id=&$1&')->lock('write')->query();
//通过lock('')开启悲观锁,传入参数read为共享锁,write为排他锁。
------
**感谢使用EASYLT 让开发更简单**
EASYLT官网:[https://www.easylt.cn](https://www.easylt.cn)