## ** EASYLT 3 框架开发手册(完全版) **
[TOC]
#### **前言**
- ##### EASYLT读音为**[ˈiːziɔːlt]**,寓意为简单、轻松、优雅的开发、维护项目,在倡导无代码、低代码的大环境下,无论是初学者还是资深开发者,都可快速上手完成项目的业务需求及进阶开发,为敏捷构建项目、API开发而生。EASYLT从项目健壮性、应用层面出发,有针对性的选择三方开源扩展、中间件,如消息队列中间件封装了RabbitMQ,更多同类中间件,如Kafka,如果有开发需求可以自行实现。
- **EASYLT框架采用全新的MSVP架构,MSVP是MVC/MVP架构的升级版,在原有的model层中增加server层,可实现业务常驻内存,用于多进程、协程的多种网络通信协议服务及RPC服务搭建,快速实现RESTful、RPC的API及覆盖web、小程序、APP等各种开发应用场景。**
- **EASYLT框架结构设计无限贴近于原生开发,将灵活性与易用性完美结合,既没有过度的封装增加更多学习、使用成本,同时足够灵活解决大部分应用业务开发场景。**
- ##### 使用前请仔细阅读以下文档,ORM(MySQL)、Swoole、RabbitMQ框架文档部分在使用时再阅读。对于之前使用过其他框架的开发者可在30-60分钟内掌握框架。
#### **EASYLT目录结构**
#### | – application
**| –** **model**
|– server
| – server.ini
(服务配置文件)
| – mysql_connect_errors.log
(异步mysql连接错误日志)
| – mysql_errors.log
(异步mysql执行错误日志)
| – (你的服务业务实现)
| – (你的模型业务实现)
**| – presenter**
| – controller
| – Index.php
(Index控制器)
| – mysql_connect_errors.log
(mysql连接错误日志)
| – mysql_errors.log
(mysql执行错误日志)
| – logic
| – (你的逻辑业务实现)
| – index.html
| – (目录保护,勿删)
**| – view**
| – start.php
(VIEW视图起始文件)
| – (你的视图业务实现)
**| – common.php**
| – (请在这里添加你的类/方法库)
**| – config.php**
| – (请在这里添加你的配置参数)
#### | – backup
(备份文件目录)
#### | – core
**| – config**
| – config.php
(全局配置文件,如数据库连接参数等)
| – config_controller.php
(控制器配置文件)
| – config_route.php
(路由配置文件)
| – config_swoole.php
(swoole服务配置文件)
| – config_rabbitmq.php
(rabbitmq服务配置文件)
**| – commin**
(公共类库目录)
**| – log**
(异常日志目录)
**| – library**
(框架服务类库)
**| – base_api.php**
(API数据返回运行基类)
**| – base_view.php**
(视图加载运行文件)
**| – route.php**
(路由解析文件)
**| – controller.php**
(控制器解析文件)
#### | – extend
| – phpexcel
(PHPExcel扩展)
| – rabbitmq
(RabbitMQ扩展)
| – whoops
(Debug扩展)
(添加你的扩展类库)
#### | – public
**| – index.php**
(入口文件)
**| – assets**
(view视图的静态加载文件,如css、js、img等)
**| – .htaccess**
(Apache路由重写,勿删勿改)
**| – nginx.htaccess**
(Nginx路由重写,勿删勿改)
**| – index.html**
(未配置.htaccess/nginx.htaccess服务器定向入口文件)
#### **框架部署**
------
##### 环境要求
- 保证**php**版本>=**7.0(建议使用7.3.4)**
- 保证**生产环境**采用**Linux centOS 7.x**或 **Ubuntu**
- 保证**web服务器**采用**Apache**或**Nginx**
- 保证**关系型数据库**采用**Mysql**
- **(可选项)**保证**缓存数据库**采用**Redis**
- **(可选项)**保证**Swoole**扩展版本>=**4.6.7**同时<**5.0**
- **(可选项)**保证**RabbitMQ**版本Distro/Version为**el/7**;**erlang**版本大于**23.2**小于**24**及Distro/Version为
**el/7**。
##### 下载部署
1、通过以下几种方式下载EASYLT:
- [https://www.easylt.cn](https://www.easylt.cn)官网直接下载,可在历史版本中下载老版本。
- Git下载指令:git clone https://github.com/myframe1002223338/easylt.git
- wget下载指令:wget https://easylt.cn/easylt.zip
- composer安装指令:composer create-project "easylt3/easylt3":"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、将下载的EASYLT框架复制到web服务器运行目录下(如Linux系统宝塔面板路径:/www/wwwroot/easylt),并设置站点运行目录为框架根目录,**注意不是public目录**。
> - **运行目录错误将无法正常运行框架,easylt框架根目录名称可自行更改。**
> - **如果生产环境使用可视化环境部署,如宝塔面板,请将框架根目录的.htaccess(采用Apache服务器时)、nginx.htaccess(采用Nginx服务器时)中内容复制到站点伪静态中。**
>
#### **使用框架**
------
##### 配置文件
- 请在EASYLT根目录打开core/config目录,在config.php中对所有配置文件进行相应的配置更改,如mysql、redis数据库连接参数等;另外请更改常量ADDRESS为你的服务器公网IP或域名配置,请以http://或https://开头。
- 开发环境下建议在config.php配置更改常量ERROR_STATE为2,显示除了E_NOTICE的所有运行错误,便于开发调试;生产环境下请务必再次配置更改为0,屏蔽运行错误,保证线上安全性。
> - **不建议配置更改为-1,这样会显示所有错误类型包含E_NOTICE,可能输出污染会造成API出参回传数据异常。**
> - **开发中新的配置请直接写入到application目录下的config.php中。**
>
##### 框架运行
- 打开浏览器输入127.0.0.1,运行成功会出现以下页面:
![](http://easylt.cn/public/assets/frame_run.png)
- 运行模式:常规WEB开发采用MVP架构即可,MSVP架构请参考以下Swoole框架文档。
![](http://www.easylt.cn/public/assets/run_pattern.png)
- 开发一个DEMO **Hello World**
**第一步** 在view视图目录下创建一个demo.php文件并写入以下示例代码:
![](http://www.easylt.cn/public/assets/view_demo.png)
**第二步** 在model模型目录下创建一个demo.php文件并写入以下示例代码:
![](http://www.easylt.cn/public/assets/model_demo.png)
**第三步** 在logic逻辑目录下创建一个demo.logic.php文件并写入以下示例代码:
> **logic逻辑文件命名为相应model模型文件名拼接 .logic,以下逻辑文档有说明。**
![](http://www.easylt.cn/public/assets/logic_demo.png)
**第四步** 打开浏览器输入http://127.0.0.1/?href=demo,成功渲染并输出hello world!
##### 模型(model)
传统MVC架构的M(model)层,用于对数据进行映射、处理。
**1、model模型目录下的文件命名规范:文件名不支持大写字母。**
2、DB操作
- model模型下用于实现业务实体类模型,实体类中对关系型数据库mysql操作可采用ORM或mysqli面向过程写法;
- 非关系型数据库redis采用原生写法。
**3、API出参回传直接调用response函数,如下:**
> **response(200,'success',$data);第一个参数为code【必须为int数据类型】、第二个参数为message【必须为string数据类型】、第三个参数为返回的数据。**
> - **API出参回传数据统一自动返回json字符串格式,如response(200,'success','hello world!');数据返回后显示为 {"code":200,"msg":"response success!","data":"hello world!"},将该json字符串解析为数组、JavaScript对象进行取值。 **
> - **默认在logic逻辑文件中API出参回传数据,如果model模型文件没有对应的logic逻辑文件,请在model模型文件中返回API数据出参回传。**
>
4、model模型复用:msvp架构模式下的logic逻辑是为了model模型复用同时与视图、控制器解耦,使得项目大部分情况可以采用一个默认Index控制器,业务逻辑单元放置到logic逻辑中,业务更改仅需对logic逻辑操作即可;如需复用model模型直接在model模型目录下创建文件并include()引入需要复用的model模型文件即可,同理如果没有对应的logic逻辑文件,请在model模型文件或controller自定义控制器中返回API数据出参回传,否则请在logic逻辑中返回API数据出参回传。
> **被复用的model文件不能直接数据出参回传,请默认都在对应logic文件中数据出参回传。**
##### 服务(server)
MSVP架构的server部分,包含于model模型目录下用于创建多进程、定时任务、各种通信协议服务器等常驻内存服务,请阅读**Swoole框架**。
##### 视图(view)
传统MVC架构的V(view)层,用于页面渲染输出。
**1、view视图目录下的文件命名规范:文件名不支持大写字母,如果文件中包含html、css、js代码,仍然后缀名为.php。**
2、view视图下的start.php为起始文件,请更换start.php的代码为项目首页、登录或注册页面。
> **请勿更改start.php文件名或删除该文件**
**3、关于view视图资源文件引入:**
- Apache/Nginx服务器支持.htaccess/nginx.htaccess时,view视图文件中引入的资源如js、css、images、fonts等目录/文件请直接放置到框架根目录下,资源文件中的路径无需进行修改。
> **如果js目录中包含.php文件,在view文件中需要引入该js下.php文件,则引入方式为如:include('../assets/js/test.php'),需要返回一个层级,否则会引入失败。**
- 当服务器不支持.htaccess/nginx.htaccess时,view视图文件中引入的资源如js、css、images、fonts等目录/文件请直接放置到框架入口文件public目录下,资源文件中的路径无需进行修改。
> **view视图文件中引入的资源文件也可以放置到public/assets资源目录下,此时需对每个view视图文件中引入资源路径前加上常量ASSETS_PATH,如果此时引入部分报错请自行调试或采用上面默认的放置方式。**
4、view视图目录下的文件跳转指定页面请调用常量VIEW_PUBLIC并拼接跳转的文件名,不包含扩展名,如跳转到view视图目录下的login.php:
```
echo '';
```
或手动输入如:
```
http://127.0.0.1/?href=login
```
> - **Apache/Nginx服务器请支持.htaccess/nginx.htaccess,否则请替换常量VIEW_PUBLIC为VIEW_PUBLIC_OTHER。**
> - **VIEW_PUBLIC常量值为服务器域名或公网IP+/?href=,如http://127.0.0.1/?href=**
> - **VIEW_PUBLIC_OTHER常量值为服务器域名或公网IP+/public/?href=,如http://127.0.0.1/public/?href=**
>
5、如需要get请求在跳转的文件名后拼接key=value,多参数用&连接,代码中用$_GET['key']取值,如:
```
echo '';
```
> **Apache/Nginx服务器请支持.htaccess/nginx.htaccess,否则请替换常量VIEW_PUBLIC为VIEW_PUBLIC_OTHER。**
##### 控制(controller)
传统MVC架构的C(controller)层,view视图与model模型之间的调配。
**1、Index控制器为通用控制器,默认无需创建新的控制器及任何改动,根据以下路由文档说明使用即可。**
> **如需在控制器中增加额外的业务处理,如API - Sign验签业务,直接在Index控制器类中的构造方法中实现即可。**
2、当业务模块化管理时,可能会自定义创建多个controller控制器,而不依赖于框架自带的Index通用控制器,如下为创建控制器示例:
- 自定义控制器【可参考以下】
class Example{**//类名请与控制器文件名对应**
public function one($public_var){ **//类方法名请与model模型文件名对应**
//$public_var数据类型为array,包含了框架变量,如数据库连接变量等,不用在类方法中再次global
引入。
//函数中写你的业务,默认在logic中完成;
response($code,$msg,$data); //调用API数据返回运行类库,该类库用于返回数据给请求方,必须实
现,方法实参为选填项,如果需要在controller控制器中返回数据请填入。第一个参数为code【数据
类型为int】、第二个参数为message【数据类型为string】、第三个参数为返回的数据【数据类型不
限】。
> **通常默认在model模型/logic逻辑中返回数据给请求方,结构请参考【框架变量-$response】**
}
public function two($public_var){
response();
}
}
- 自定义控制器的公共类的自动加载:
> **当我们定义了多个控制器时,有一些公共类需要统一维护,而不需要在每个控制器中重复维护,此时直接将类写入Index控制器中并在指定控制器中继承类即可。**
##### 路由(route)
1、路由示例:http://127.0.0.1/m/v/p/index/model/param/key1=value&key2=value
- m/为application应用目录路径
- v/p/为presenter/controller/控制器目录路径
- index/为Index控制器文件名,不包含.php扩展名,如自定义控制器请更换index为自定义控制器名称;
- model/为model模型目录下指定文件名,不包含.php扩展名;
- param/为路由参数,用于判断model文件下多接口业务分发对接,用$query_param[‘key’],取值可选项;
- key1=value为get请求入参,多参数用&连接,用$query_get['key']取值,可选项;
**默认已对路由进行重写,Apache/Nginx服务器请支持.htaccess/nginx.htaccess,否则请按照以下写法:**
http://127.0.0.1/application/presenter/controller/example.php/model/param/?key1=value&key2=value
2、路由重写
2.1 在config_route.php路由配置文件中修改常量ROUTE_RUN的值为1,开启配置运行;
2.2 在config_route.php路由配置文件中修改常量API_URL_ROUTE的各个值用于API-URI重写;
2.3 在config_route.php路由配置文件中修改常量APPLICATION_RENAME的各个值用于改变application下各个初始化目录名;
> **修改后目录名为修改的目录名+下划线+目录标识,如controller目录名改为init,则修改后控制器目录名为init_controller;如果将目录名改为初始值,即model、server、presenter、controller、logic、view,则目录名不会拼接+下划线+目录标识,恢复初始化目录名。**
2.4 通过浏览器运行框架入口文件,如访问http://127.0.0.1则以上配置即可生效;
2.5 在config_route.php路由配置文件中修改常量ROUTE_RUN的值为0,关闭配置运行。
> **路由重写后路由URI将改变,如下:**
>
> - **更改常量API_URL_ROUTE各个值并生效后,当服务器支持.htaccess/nginx.htaccess时,路由URI中的M/V/P需替换为相应更改值。**
>
> - **更改常量APPLICATION_RENAME各个值并生效后,当服务器不支持.htaccess/nginx.htaccess时,路由URI中的路径需替换为相应更改值。如:**
>
> http://127.0.0.1/application/presenter/controller/index.php/model
>
> **当更改application/presenter/controller目录名后在路由URI中需相应替换**
>
**3、服务器.htaccess/nginx.htaccess支持:**
Apache服务器的路由重定向文件为框架根目录下的.htaccess,Nginx服务器的路由重定向文件为框架根目录下的nginx.htaccess。Apache默认支持.htaccess,如果不支持请自行配置解决;Nginx默认不支持nginx.htaccess,请按照以下方法配置。
- 打开Nginx服务器的vhosts.conf,在该配置文件中引入nginx.htaccess,如下标黑部分为引入项,注意路径:
server {
listen 80;
server_name localhost;
root "D:/wamp/www/easylt";
location / {
index index.php index.html;
error_page 400 /error/400.html;
error_page 403 /error/403.html;
error_page 404 /error/404.html;
error_page 500 /error/500.html;
error_page 501 /error/501.html;
error_page 502 /error/502.html;
error_page 503 /error/503.html;
error_page 504 /error/504.html;
error_page 505 /error/505.html;
error_page 506 /error/506.html;
error_page 507 /error/507.html;
error_page 509 /error/509.html;
error_page 510 /error/510.html;
autoindex off;
**include D:/wamp/www/easylt/nginx.htaccess;**
}
location ~ \.php(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
}
- 如果项目采用宝塔等面板,可以复制nginx.htaccess中的内容到站点-设置-伪静态中即可。
- 首次配置nginx.htaccess或后续路由重写都需重启Nginx服务器才可生效。
##### 逻辑(logic)
MVC架构升级为MVP后,C(controller)层衍变为P(presenter)层,包含controller控制层与logic逻辑层;逻辑层用于解耦model模型、controller控制器、view视图,将业务逻辑在logic逻辑文件中处理。
**1、logic逻辑目录下的文件命名规范:文件名不支持大写字母,logic文件命名为model相应文件名拼接.logic,**如model文件名为login.php,则logic相应文件名必须为login.logic.php。
**2、在logic逻辑文件中写业务可以直接调用相应model模型文件中的变量、函数、类、类方法、类属性。**
**3、API出参回传直接调用response函数,如下:**
> **response(200,'success',$data);第一个参数为code【必须为int数据类型】、第二个参数为message【必须为string数据类型】、第三个参数为返回的数据。**
> - **API出参回传数据统一自动返回json字符串格式,如response(200,'success','hello world!');数据返回后显示为 {"code":200,"msg":"response success!","data":"hello world!"},将该json字符串解析为数组、JavaScript对象进行取值。 **
> - **默认在logic逻辑文件中API出参回传数据,如果model模型文件没有对应的logic逻辑文件,请在model模型文件中返回API数据出参回传。**
##### 助手函数
【日志】
用于抛异常时对异常、错误信息的记录,直接在业务中调用onerror($message,$path);方法即可。
- $message为必填项,为异常、错误信息。
- $path为选填项,为log文件路径。当不传入该参数时,异常、错误信息自动写入core/log/errors.log中。
- 当传入$path时,值为:ERRORS_PATH.'log文件名',此时异常、错误信息会写入到core/log/指定log文件中。
【打印】
可以通过dump($var,$label)打印数据,更好的格式显示。
- $var为必填项,支持各种数据类型。
- $label为选填项,为打印时的前缀标签。
> **开发中封装的类/方法库请直接写入到application目录下的common.php中。**
##### 框架变量
- **$request**
【应用层:contoller、model、logic】请求的入参数据,数据类型为array,根据键值对取值。如API入参的
json字符串数据为{"username":"liteng"},则在model文件中$request['username']的值为liteng。
- **$response**
【应用层:model、logic】在model或logic文件中的API出参回传数据变量,且格式如下:
$response = [$code,$msg,$data];第一个元素为code【数据类型为int】、第二个元素为message【数据类
型为string】、第三个元素为返回的数据【数据类型不限】。
> response($code,$msg,$data);可以替代$response = [$code,$msg,$data];
- **$query_param**
【应用层:controller、model、logic】用于判断同一文件下多接口业务分发对接,如以下API请求URL:
http://127.0.0.1/m/v/p/index/login/one ,$query_param的值为one。
- **$query_get**
【应用层:controller、model、logic】获取API请求URL中的GET参数,数据类型为array,根据键值对取
值。如以下URL:
http://127.0.0.1/m/v/p/index/login/frame=easylt&username=liteng
$query_get['frame']的值为easylt,$query_get['username']的值为liteng
- **$mysql_conn**
【应用层:model】mysql连接变量,采用mysqli面向过程写法,在model目录文件中使用。
- **$mysql_orm**
【应用层:model】mysql-orm操作变量,在model目录文件中使用,具体操作请阅读**ORM**部分文档。
- **$redis**
【应用层:model】redis连接变量,在model目录文件中使用。
- **$curl_post**
【应用层:view、controller、model、logic】curl数据传输post请求模式,应用示例如下:
$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;
- **$curl_get**
【应用层:view、controller、model、logic】curl数据传输get请求模式,应用示例如下:
$result = $curl_get->get($url,$headers),第一个参数为目标文件的url、第二个参数为头信息请求参数(非
必填),$result为请求返回值。
//$headers的数据类型必须为array,且为一维数组,元素值用冒号分隔键值对,如:['Authorization:init']
- **$headers_message**
【应用层:controller、model、logic】获取头信息请求参数,数据类型为array,如获取头信息请求参数中的
Authorization值:$headers_message['Authorization']
- **$excel**
【应用层:controller、model、logic】获取头信息请求参数,数据类型为array,如获取头信息请求参数中的
【应用层:controller、model、logic】获取PHPExcel实例化对象变量,框架引入PHPExcel类库,用于处理
Excel数据业务。
##### 框架常量
常量值可在core/config目录下的config.php中进行配置
- **ADDRESS:**服务器公网IP或域名,如https://www.easylt.cn
- **API_URL:**Index通用控制器下的API接口地址,Apache/Nginx服务器请支持.htaccess/nginx.htaccess。在VIEW视图中请求API时,在API_URL常量后拼接接口名称(model模型文件名),如API_URL.'login'。
- **API_URL_OTHER:**同上,当Apache/Nginx服务器不支持.htaccess/nginx.htaccess时,用此常量。
- **VIEW_PUBLIC:**入口加载文件地址,Apache/Nginx服务器请支持.htaccess/nginx.htaccess。加载VIEW视图时,在VIEW_PUBLIC常量后拼接view视图文件名,如VIEW_PUBLIC.'login'。
- **VIEW_PUBLIC_OTHER:**同上,当Apache/Nginx服务器不支持.htaccess/nginx.htaccess时,用此常量。
- **ROOT_PATH:**地址指向框架根目录
- **APP_PATH:**地址指向application目录
- **EXTEND_PATH:**地址指向extend目录
- **CORE_PATH:**地址指向core目录
- **ASSETS_PATH:**view视图静态资源路径,地址指向/public/assets/
- **LIB_PATH:**lib类库目录路径,地址指向/core/lib/
- **ERRORS_PATH:**log日志目录路径,地址指向/core/log/
- **D:**路径分隔符
##### **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(),操作模式后的类方法顺序请按照文档顺序调用。
> **有两种写法,可组装或分组,$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为排他锁。
##### **Swoole框架**
1、Swoole是一个多进程、支持协程的服务器、客户端php扩展,支持TCP、UDP、HTTP,WebSocket协议及RPC远程过程调用服务器、客户端的实现。EASYLT对其进行高度封装,使开发变得更简单、可靠。如需单独在其他php框架或原生php开发中使用Swoole开发项目可在官网下载Swoole新手包,在技术支持-新手包系列中选择Swoole新手包进入并下载。
Tips:感谢韩天峰老师的开源项目Swoole
2、请在php中安装Swoole扩展,版本>=**4.6.7**同时<**5.0**,打开core/config目录下的config_swoole.php,对相应的服务器、客户端配置文件进行相应的修改,配置文件中对每一项参数有详细说明。默认已配置好每一项,通常无需再次配置。
3、服务运行模式
![](http://easylt.cn/public/assets/run_pattern_server.png)
> **服务器、客户端中不可创建容器,如多进程、协程/异步Mysql/Redis容器,但多进程容器中可以包含服务器、客户端、协程/异步Mysql/Redis容器。**
4、DB操作
- **view视图下可直接创建WebSocket、RPC、TCP、UDP、HTTP客户端,但无法操作DB。**
- **model模型下创建的TCP、UDP、HTTP、RPC客户端和model模型常规实体类一样支持Mysql的mysqli面向过程、ORM的DB操作及redis的原生DB操作。**
- **server服务下创建的服务支持异步Mysql、异步Redis、同步Mysql、同步Redis的DB操作;服务器中的TASK异步任务仅支持同步Mysql、同步Redis。**
- **异步Mysql、异步Redis、同步Mysql、同步Redis具体操作请阅读Swoole框架相关文档。**
###### TCP服务器
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建服务器【必须实现】
$tcp_serv = new Tcp_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
> **当填入$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客户端
- 引入服务器配置文件【WEB服务器(FPM)运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建客户端【必须实现】
$tcp_cli = new Tcp_client($ip,$port);
//$ip为服务器ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
> **当填入$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中的常量值。
> **当填入$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(function($state,$task_id,$reactor_id){
//$state为task异步任务运行结果状态,当$state等于true时,异步任务运行完成。
//$task_id为异步任务ID
//$reactor_id为异步任务线程ID
//匿名回调函数中写你的业务
});
- 启动服务器【必须实现】
$udp_serv->start();
###### UDP客户端
- 引入服务器配置文件【WEB服务器(FPM)运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建客户端【必须实现】
$udp_cli = new Udp_client($ip,$port);
//$ip为服务器ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
> **当填入$ip时,必须填入$port;当填入$port时,可忽略$ip,如:new Udp_client('',9501);**
- 像服务器发送数据【必须实现】
$udp_cli->send(function(){
//匿名回调函数中写你的业务
//如需发送数据请return $var
});
- 从服务器接收数据【必须实现】
$udp_cli->receive(function($response_data){
//$response_data为服务器返回的数据
//匿名回调函数中写你的业务
});
###### HTTP服务器
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建服务器【必须实现】
$http_serv = new Http_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
> **当填入$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客户端
- 引入服务器配置文件【WEB服务器(FPM)运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建客户端【必须实现】
$http_cli = new Http_client($ip,$port);
//$ip为服务器ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
> **当填入$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服务器
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建服务器【必须实现】
$websocket_serv = new Websocket_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
> **当填入$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为客户端发送的数据
> **开发一对一发送消息业务时,客户端连接成功时服务器端将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接口效率更高,适用于大型系统、多系统间的业务往来。
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建服务器【必须实现】
$rpc_serv = new Rpc_server($ip,$port);
//$ip为服务器监听ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
> **当填入$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客户端
- 引入服务器配置文件【WEB服务器(FPM)运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建客户端【必须实现】
$rpc_cli = new Rpc_client($ip,$port);
//$ip为服务器ip地址,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
//$port为服务器端口号,选填项,当不填入时自动填入配置文件config_swoole.php中的常量值。
> **当填入$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();
###### 多进程
- 仅支持在server目录下服务文件中创建,有两种创建模式,分别为单独进程模式与进程池模式:**单独进程模式的进程间通信支持QUEUE消息队列;进程池模式的进程间通信支持PIPE管道。**
**//进程模式通过$process>create()中的第二个参数切换,'single'为单独进程模式,'pool'为进程池模式。**
**单独进程模式:**
- 引入服务器配置文件【必须实现】
include('server.ini');
- 实例化进程【必须实现】
$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');
**进程池模式:**
> **pool进程池模式下请勿在进程中创建如TCP等服务器,进程池模式适用于处理有状态消费业务,如从消息队列中读取消息并消费。需要在进程容器中创建如TCP等服务器请选择single单独进程模式。**
- 引入服务器配置文件【必须实现】
include('server.ini');
- 实例化进程【必须实现】
$process = new Process;//进程池模式运行为异步非阻塞模式,进程间用PIPE管道通信。
- 创建进程池【必须实现】
$process->create(function($process){
//$process为进程对象
//匿名回调函数中写你的业务
//如需写入数据到PIPE管道请return $var
},'pool');
- 读取PIPE管道中的数据【可选项】
$process->pipe(function($response_data){
//匿名回调函数中写你的业务
//$response_data为读取PIPE管道中的数据
});
###### 协程
- 仅支持在server目录下服务文件中创建
include('server.ini');
new Async(function($channel){
**//通过new Async()创建协程容器,将协程放置到容器的匿名回调函数中自动实现异步。**
**//$channel为协程通信通道变量。**
**PS:**
**1、在new Async()协程容器中创建协程才可自动实现异步,但协程容器不可在服务器中创建,如TCP服务器,**
**会发生冲突导致运行错误。**
**2、未创建协程容器时,在配置文件config_swoole.php中配置常量ASYNC_CO开启异步协程同样使协程自动实**
**现异步。**
**3、以下异步Mysql、异步Redis、异步cURL基于协程开发,用法同理;通过异步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
- 仅支持在server目录下服务文件中创建。
- 当在如TCP等服务器、协程(不包含多进程容器)容器中创建异步Mysql时,无需创建异步Mysql容器,直接创建异步Mysql,否则会报错。
- 调用匿名函数外的变量请使用闭包写法(同步Mysql同理),如:
new Async_mysql(function()use($var){Async_mysql::co($mysql_conn,$mysql_orm)use($var){}});
include('server.ini');
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运行周期时间,以秒为单位,非必填项,可自行设置值;**
> **如果不设置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
- 仅支持在server目录下服务文件中创建。
- 当在如TCP等服务器、协程(不包含多进程容器)容器中创建异步Redis时,无需创建异步Redis容器,直接创建异步Redis,否则会报错。
- 调用匿名函数外的变量请使用闭包写法(同步Redis同理),如:
new Async_redis(function()use($var){Async_redis::co($mysql_conn,$mysql_orm)use($var){}});
include('server.ini');
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运行周期时间,以秒为单位,非必填项,可自行设置值;**
> **如果不设置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
- 仅支持在server目录下服务文件中创建
include('server.ini');
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服务器为例:
include('server.ini');
$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();
###### 定时任务
- 仅支持在server目录下服务文件中创建
- 多个定时任务在TCP等服务器/协程容器中,将异步非阻塞执行。
- 有两种定时器模式,**循环执行定时器** 与 **单次执行定时器**,如下:
include('server.ini');
$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();
##### **RabbitMQ框架**
1、RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件,亦称面向消息的中间件,可实现以下模式的消息队列业务,同时具有消息确认机制:simple/worker、fanout、routing、topic、dead。EASYLT对其进行高度封装,使开发变得更简单、可靠。
2、请下载、安装**RabbitMQ(版本Distro/Version为el/7)**与**erlang(版本大于23.2小于24及Distro/Version**
**为el/7)**,配置并启动RabbitMQ-server服务器。
3、RabbitMQ生产者、消费者运行模式
**生产者**
- **model:**生产者文件在model模型中创建时,view视图下文件(如AJAX请求)或外部系统调用API接口映射到model模型目录下的生产者文件时,进行消息生产。
- **server:**生产者文件在server服务中创建时,仅可通过CLI命令台运行,可配合Swoole的各种服务器、多进程实现内存常驻运行进行消息生产。
**消费者**
- **model:**消费者文件仅**simple/worker模式**下可在model模型中创建,且**消费模式必须为即刻模式**,默认为等待模式,如需更改请在core/config目录下config_rabbitmq.php中配置。创建后,view视图下文件(如AJAX请求)或外部系统调用API接口映射到model模型目录下的消费者文件时,进行消息消费。
- **server:**消费者文件在server服务中创建时,仅可通过CLI命令台运行,可配合Swoole的各种服务器、多进程实现内存常驻运行进行消息消费。
> **在server服务下运行RabbitMQ文件,当配置文件config_swoole.php中配置常量ASYNC_CO为开启异步协程时,运行RabbitMQ文件必须在容器中,即在如TCP等服务器或协程容器中(不含多进程容器,当放置多进程容器中也需包含服务器或协程容器),否则会发生冲突导致运行错误。**
4、DB操作
- **model模型下创建的生产者及simple/worker模式的消费者文件和model模型常规实体类一样支持Mysql的mysqli面向过程、ORM的DB操作及redis的原生DB操作。**
- **server服务下创建的生产者、消费者文件支持异步Mysql、异步Redis、同步Mysql、同步Redis的DB操作;生产者、消费者文件在如TCP服务器的TASK异步任务中仅支持同步Mysql、同步Redis。**
- **异步Mysql、异步Redis、同步Mysql、同步Redis具体操作请阅读Swoole框架相关文档。**
###### simple/worker模式生产者
simple模式的生产者、消费者为一对一;worker模式的生产者、消费者为一对多,多个消费者依次读取、消费消息队列中的消息。
- 引入服务器配置文件【WEB服务器运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建生产者【必须实现】
$simple_producter = new Simple_producter($v_host,$queue);
//$v_host为Virtual host用户名
//$queue为消息队列名称
- 推送消息到队列中【必须实现】
$simple_producter->push(function(){
//匿名回调函数中写你的业务
//推送消息到队列中请return $var
});
###### simple/worker模式消费者
- 引入服务器配置文件【WEB服务器运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建消费者【必须实现】
$simple_consumer = new Simple_consumer($v_host,$queue);
//$v_host为Virtual host用户名
//$queue为消息队列名称
- 从消息队列中取消息【必须实现】
$simple_consumer->pop(function($response_data){
//匿名回调函数中写你的业务
//$response_data为读取消息队列中的数据
//读取消息后需确认成功消费消息请**return true**,否则读取消息后,该条消息仍然保持在消息队列中;
});
###### fanout模式生产者
fanout模式的生产者、消费者为一对一或一对多,多个消费者同时读取、消费消息队列中的相同的消息,请同时开启多个消费者并内存常驻运行,且**消费模式建议为等待模式**,默认为等待模式。
- 引入服务器配置文件【WEB服务器运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建生产者【必须实现】
$fanout_producter = new Fanout_producter($v_host,$exchange);
//$v_host为Virtual host用户名
//$exchange为消息队列交换器名称
- 推送消息到交换器中【必须实现】
$fanout_producter->push(function(){
//匿名回调函数中写你的业务
//推送消息到交换器中请return $var
});
###### fanout模式消费者
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建消费者【必须实现】
$fanout_consumer = new Fanout_consumer($v_host,$exchange,$queue);
//$v_host为Virtual host用户名
//$exchange为消息队列交换器名称,保持与生产者一致;
//$queue为消息队列名称,默认可不填写该参数,系统会自动创建临时消息队列,消费者文件进程结束后临时消息队列自动删除。如需对消息队列持久化处理,请在core/config目录下config_rabbitmq.php中配置消息队列为持久化模式并填写该参数。
- 从消息队列中取消息【必须实现】
$fanout_consumer->pop(function($response_data){
//匿名回调函数中写你的业务
//$response_data为读取消息队列中的数据
//读取消息后需确认成功消费消息请**return true**,否则读取消息后,该条消息仍然保持在消息队列中;
});
###### routing(direct)模式生产者
routing模式的生产者、消费者为一对一或一对多,多个消费者根据routing匹配同时读取、消费消息队列中的相同的消息,请同时开启多个消费者并内存常驻运行,且**消费模式建议为等待模式**,默认为等待模式。
- 引入服务器配置文件【WEB服务器运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建生产者【必须实现】
$routing_producter = new Routing_producter($v_host,$exchange,$routing);
//$v_host为Virtual host用户名
//$exchange为消息队列交换器名称
//$routing为生产者、消费者与消息队列相互匹配的key
- 推送消息到交换器中【必须实现】
$routing_producter->push(function(){
//匿名回调函数中写你的业务
//推送消息到交换器中请return $var
});
###### routing(direct)模式消费者
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建消费者【必须实现】
$routing_consumer = new Routing_consumer($v_host,$exchange,$routing,$queue);
//$v_host为Virtual host用户名
//$exchange为消息队列交换器名称,保持与生产者一致;
//$routing为生产者、消费者与消息队列相互匹配的key
//$queue为消息队列名称,默认可不填写该参数,系统会自动创建临时消息队列,消费者文件进程结束后临时消息队列自动删除。如需对消息队列持久化处理,请在core/config目录下config_rabbitmq.php中配置消息队列为持久化模式并填写该参数。
- 从消息队列中取消息【必须实现】
$routing_consumer->pop(function($response_data){
//匿名回调函数中写你的业务
//$response_data为读取消息队列中的数据
//读取消息后需确认成功消费消息请**return true**,否则读取消息后,该条消息仍然保持在消息队列中;
});
###### topic模式生产者
topic模式的生产者、消费者为一对一或一对多,多个消费者根据topic通配符匹配同时读取、消费消息队列中的相同的消息,请同时开启多个消费者并内存常驻运行,且**消费模式建议为等待模式**,默认为等待模式。
- 引入服务器配置文件【WEB服务器运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建生产者【必须实现】
$topic_producter = new Topic_producter($v_host,$exchange,$topic);
//$v_host为Virtual host用户名
//$exchange为消息队列交换器名称
//$topic为生产者、消费者与消息队列相互匹配的通配符
- 推送消息到交换器中【必须实现】
$topic_producter->push(function(){
//匿名回调函数中写你的业务
//推送消息到交换器中请return $var
});
###### topic模式消费者
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建消费者【必须实现】
$topic_consumer = new Topic_consumer($v_host,$exchange,$topic,$queue);
//$v_host为Virtual host用户名
//$exchange为消息队列交换器名称,保持与生产者一致;
//$topic为生产者、消费者与消息队列相互匹配的通配符
//$queue为消息队列名称,默认可不填写该参数,系统会自动创建临时消息队列,消费者文件进程结束后临时消息队列自动删除。如需对消息队列持久化处理,请在core/config目录下config_rabbitmq.php中配置消息队列为持久化模式并填写该参数。
- 从消息队列中取消息【必须实现】
$topic_consumer->pop(function($response_data){
//匿名回调函数中写你的业务
//$response_data为读取消息队列中的数据
//读取消息后需确认成功消费消息请**return true**,否则读取消息后,该条消息仍然保持在消息队列中;
});
###### dead(死信队列)模式生产者
dead(死信队列)模式的生产者、消费者为一对一或一对多,多个消费者根据routing匹配同时读取、消费消息队列中的相同的消息,请同时开启多个消费者并内存常驻运行,且**消费模式建议为等待模式**,默认为等待模式。
- 引入服务器配置文件【WEB服务器运行无需实现 **server服务**的CLI模式运行必须实现】
include('server.ini');
- 创建生产者【必须实现】
$dead_producter =
new Dead_producter($v_host,$exchange,$dead_exchange,$routing,$dead_routing,$queue,
$dead_queue,$ttl);
//$v_host为Virtual host用户名
//$exchange为正常消息队列交换器名称
//$dead_exchange为死信消息队列交换器名称
//$routing为生产者、消费者与正常消息队列相互匹配的key
//$dead_routing为生产者、消费者与死信消息队列相互匹配的key
//$queue为正常消息队列名称
//$dead_queue为死信消息队列名称
//$ttl为正常消息队列中消息的过期时间,后期后自动转入死信消息队列中;
- 推送消息到正常消息队列交换器中【必须实现】
$dead_producter->push(function(){
//匿名回调函数中写你的业务
//推送消息到交换器中请return $var
});
###### dead(死信队列)模式消费者
- 引入服务器配置文件【必须实现】
include('server.ini');
- 创建消费者【必须实现】
$dead_consumer = new Dead_consumer($v_host,$dead_exchange,$dead_routing,$dead_queue);
//$v_host为Virtual host用户名
//$dead_exchange为死信消息队列交换器名称,保持与生产者一致;
//$dead_routing为生产者、消费者与死信消息队列相互匹配的key
//$dead_queue为死信消息队列名称,保持与生产者一致;
//以上三个参数为死信消息队列参数时,可实现延迟队列,也可以替换三个参数为正常消息队列参数,则可以在消息过期前去正常消息队列中读取、消费消息;
- 从消息队列中取消息【必须实现】
$dead_consumer->pop(function($response_data){
//匿名回调函数中写你的业务
//$response_data为读取消息队列中的数据
//读取消息后需确认成功消费消息请**return true**,否则读取消息后,该条消息仍然保持在消息队列中;
});
------
**感谢使用EASYLT 让开发更简单**
EASYLT官网:[https://www.easylt.cn](https://www.easylt.cn)