## **logo 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)