diff --git a/README.md b/README.md index 44ea1efce1fd7f6b233ceb59a5a3a0e924c646fd..078df861ff2ac4294245288e31608a067f5373a9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ # One - 一个极简的基于swoole常驻内存框架 -> 支持在fpm下运行 +## 背景 +在用过`laravel`框架,发现它的`路由`和`数据库ORM`确实非常好用,但是整体确实还有点慢,执行到控制器大于需要耗时60ms左右。于是打算做一个拥有非常好用的路由和orm又非常简单的框架。所以你会发现one框的`路由`和`ORM`有laravel的影子。但也有一些自己的特色,例如`ORM`支持自动化缓存(自动化读、写、刷新)保持与数据库同步,对外使用无感知。更多功能请看文档。one框架在fpm下整体耗时在`1ms`左右。 -## 安装&运行 + +## hello world + +安装 ```shell composer create-project lizhichao/one-app app @@ -10,15 +14,22 @@ cd app php App/swoole.php ``` +测试 + +```shell +curl http://127.0.0.1:8081/ +``` + ## 主要功能 - RESTful路由 - 中间件 -- WS/TCP……任意协议路由 +- websocket/tcp/http……任意协议路由 - ORM模型 -- SQL日志模板 -- MYSQL连接池 -- REDIS连接池 +- 统一的session处理 +- mysql连接池 +- redis连接池 +- tcp连接池 - HTTP/TCP/WEBOSCKET/UDP服务器 - 缓存 - 进程间内存共享 @@ -26,12 +37,6 @@ php App/swoole.php - 日志 - RequestId跟踪 -## 支持的运行环境 - -- `apache/php-fpm`的常规环境 -- 基于`swoole`的阻塞环境 -- 基于`swoole`的全协程环境 - [详细文档地址](https://www.kancloud.cn/vic-one/php-one/826876) @@ -42,6 +47,7 @@ QQ交流群: 731475644 ## 路由 ```php + Router::get('/', \App\Controllers\IndexController::class . '@index'); // 带参数路由 @@ -49,8 +55,21 @@ Router::get('/user/{id}', \App\Controllers\IndexController::class . '@user'); // 路由分组 Router::group(['namespace'=>'App\\Test\\WebSocket'],function (){ - Router::set('ws','/a','TestController@abc'); // websocket 路由 - Router::set('ws','/b','TestController@bbb'); // websocket 路由 + // websocket 路由 + Router::set('ws','/a','TestController@abc'); + Router::set('ws','/b','TestController@bbb'); +}); + +// 中间件 +Router::group([ + 'middle' => [ + \App\Test\MixPro\TestMiddle::class . '@checkSession' + ] +], function () { + Router::get('/mix/ws', HttpController::class . '@ws'); + Router::get('/mix/http', HttpController::class . '@http'); + Router::post('/mix/http/loop', HttpController::class . '@httpLoop'); + Router::post('/mix/http/send', HttpController::class . '@httpSend'); }); ``` @@ -63,103 +82,219 @@ namespace App\Model; use One\Database\Mysql\Model; +// 模型里面不需要指定主键,框架会缓存数据库结构 +// 自动匹配主键,自动过滤非表结构里的字段 class User extends Model { + // 定义模型对应的表名 CONST TABLE = 'users'; + // 定义关系 public function articles() { return $this->hasMany('id',Article::class,'user_id'); } + + // 定义事件 + // 是否开启自动化缓存 + // …… } ``` ### 使用 -在fpm下数据库连接为单列, -在swoole模式下数据库连接自动切换为连接池 +在`fpm`下数据库连接为单列, +在`swoole`模式下数据库连接自动切换为连接池 ```php // 查询一条记录 -User::find(1); +$user = User::find(1); // 关联查询 -User::whereIn('id',[1,2,3])->with('articles')->findAll(); +$user_list = User::whereIn('id',[1,2,3])->with('articles')->findAll(); // 更新 -user::where('id',1)->update(['name' => 'aaa']); - -``` - -## 日志 -```php -Log::debug('abc'); -Log::debug(['12,312']); +$r = $user->update(['name' => 'aaa']); +// 或者 +$r = user::where('id',1)->update(['name' => 'aaa']); +// $r 为影响记录数量 -// 等级|时间|requestId|文件路径:行号|内容 -// DEBUG|2018-11-23 15:01:26|WelxrVb5UEoFaDrQ59XnQ|/Controllers/IndexController.php:12|abc -// DEBUG|2018-11-23 15:01:26|WelxrVb5UEoFaDrQ59XnQ|/Controllers/IndexController.php:13|["12,312"] ``` ## 缓存 ```php -Cache::set('a',1); +// 设置缓存 +Cache::set('ccc',1); -// ccc 在 tag1标签下 -Cache::set('ccc',3,['tag1']); +// 获取 +Cache::get('ccc'); -// 刷新 tag1 下的所有缓存 -Cache::flush('tag1'); -``` +// 或者 缓存ccc 过期10s 在tag1下面 +Cache::get('ccc',function (){ + return '缓存的信息'; +},10,['tag1']); -## session -``` -$this->session()->get('aaa'); -$this->session()->set('aaa',123); +// 刷新tag1下的所有缓存 +Cache::flush('tag1'); ``` -## 添加一个webSocket服务监听 +## HTTP/TCP/WEBOSCKET/UDP服务器 -需要开启什么事件就 重写父类相应事件 +启动一个websocket服务器, +添加http服务监听, +添加tcp服务监听 ```php [ - 'port' => 8082, - 'action' => \App\Server\AppWsServer::class, //类名 作为server自带继承 WsServer ;作为监听添加继承 \One\Swoole\Listener\Ws - 'type' => SWOOLE_SOCK_TCP, - 'ip' => '0.0.0.0', - 'set' => [ - 'open_http_protocol' => false, - 'open_websocket_protocol' => true + // 主服务器 + 'server' => [ + 'server_type' => \One\Swoole\OneServer::SWOOLE_WEBSOCKET_SERVER, + 'port' => 8082, + // 事件回调 + 'action' => \One\Swoole\Server\WsServer::class, + 'mode' => SWOOLE_PROCESS, + 'sock_type' => SWOOLE_SOCK_TCP, + 'ip' => '0.0.0.0', + // swoole 服务器设置参数 + 'set' => [ + 'worker_num' => 5 + ] + ], + // 添加监听 + 'add_listener' => [ + [ + 'port' => 8081, + // 事件回调 + 'action' => \App\Server\AppHttpPort::class, + 'type' => SWOOLE_SOCK_TCP, + 'ip' => '0.0.0.0', + // 给监听设置参数 + 'set' => [ + 'open_http_protocol' => true, + 'open_websocket_protocol' => false + ] + ], + [ + 'port' => 8083, + // 打包 解包协议 + 'pack_protocol' => \One\Protocol\Text::class, + // 事件回调 + 'action' => \App\Test\MixPro\TcpPort::class, + 'type' => SWOOLE_SOCK_TCP, + 'ip' => '0.0.0.0', + // 给监听设置参数 + 'set' => [ + 'open_http_protocol' => false, + 'open_websocket_protocol' => false + ] + ] ] -] +]; + + +``` + +## RPC + +### 服务端 +例如有个类`Abc` + +```php + +class Abc +{ + private $a; + + // 初始值 + public function __construct($a = 0) + { + $this->a = $a; + } + + // 加法 + public function add($a, $b) + { + return $this->a + $a + $b; + } + + public function time() + { + return date('Y-m-d H:i:s'); + } + + // 重新设初始值 + public function setA($a) + { + $this->a = $a; + return $this; + } +} ``` +把`Abc`添加到rpc服务 -## 添加一个TCP服务监听 +```php -需要开启什么事件就 重写父类相应事件 +// 添加Abc到rpc服务 +RpcServer::add(Abc::class); + +// 如果你不希望把Abc下的所有方法都添加到rpc服务,也可以指定添加。未指定的方法客户端无法调用. +//RpcServer::add(Abc::class,'add'); + +// 分组添加 +//RpcServer::group([ +// // 中间件 在这里可以做 权限验证 数据加解密 等等 +// 'middle' => [ +// TestMiddle::class . '@aa' +// ], +// // 缓存 如果设置了 当以同样的参数调用时 会返回缓存信息 不会真正调用 单位秒 +// 'cache' => 10 +//], function () { +// RpcServer::add(Abc::class); +// RpcServer::add(User::class); +//}); +``` + +### 客户端调用 + +为了方便调用我们建立一个映射类(one框架可自动生成) ```php +class ClientAbc extends RpcClientHttp { -[ - 'port' => 8083, - 'protocol' => \One\Protocol\Text::class, // 协议 - 'action' => \App\Test\MixPro\TcpPort::class, //类名 作为server自带继承 TcpServer ;作为监听添加继承 \One\Swoole\Listener\Tcp - 'type' => SWOOLE_SOCK_TCP, - 'ip' => '0.0.0.0', - 'set' => [ - 'open_http_protocol' => false, - 'open_websocket_protocol' => false - ] -] + // rpc服务器地址 + protected $_rpc_server = 'http://127.0.0.1:8081/'; + // 远程的类 不设置默认为当前类名 + protected $_remote_class_name = 'Abc'; +} ``` +调用rpc服务器的方法, 和调用本项目的方法一样的。你可以想象这个方法就在你的项目里面。 -[详细文档地址](https://www.kancloud.cn/vic-one/php-one/826876) +```php +$abc = new ClientAbc(5); -[使用列子-DEMO](https://github.com/lizhichao/one-demo) +// $res === 10 +$res = $abc->add(2,3); -QQ交流群: 731475644 +// $res === 105 +$res = $abc->setA(100)->add(2,3); +``` + +上面是通过http协议调用的。你也可以通过其他协议调用。例如Tpc协议 + +```php +class ClientAbc extends RpcClientTcp { + + // rpc服务器地址 + protected $_rpc_server = 'tcp://127.0.0.1:8081/'; + + // 远程的类 不设置默认为当前类名 + protected $_remote_class_name = 'Abc'; +} +``` + +其中类 `RpcClientHttp`,`RpcClientTcp`在框架里。 +你可以复制到任何其他地市使用。