lizhichao / one
一个极简的PHP框架,支持在fpm或swoole协程模式下运行
2.3.1
2022-12-13 03:10 UTC
Requires
- php: >=7.1
- ext-json: *
- ext-pdo: *
- lizhichao/one-ck: >=0.1.11
Suggests
- ext-msgpack: globalData和Rpc服务通讯的打包
- ext-pdo: pdo数据库驱动
- ext-redis: 如果缓存驱动为Redis
- ext-swoole: 常驻内存运行必须的扩展
README
One - 一个支持[swoole | php-fpm]环境的极简高性能PHP框架
- 快速 - 即使在php-fpm环境下也能在
1ms
内响应用户请求 - 简单 - 让您专注于使用one做什么,而不是如何使用one
- 灵活 - 每个组件松散耦合,可以灵活匹配和使用,使用方法一致
- 原生SQL可以与模型关系
with
一起使用,关系可以跨数据库类型 - session可以在http、websocket或甚至tcp、udp和cli下使用
- ...
- 原生SQL可以与模型关系
- 高效 - 运行性能、开发效率和易于维护
- 轻量级 - 无其他依赖,路由和orm所有组件的总代码量不超过500k。如果没有复杂调用关系,可以快速掌握设计原则
- 子数据库和子表 - 支持无线子数据库和表,上层使用方法保持不变
hello world
安装
composer create-project lizhichao/one-app app cd app php App/swoole.php # stop : `php App/swoole.php -o stop` # reload : `php App/swoole.php -o reload` # Daemon start : `php App/swoole.php -o start` curl http://127.0.0.1:8081/
性能
参考:
主要组件
- 路由器
- 支持贪婪匹配和优先级
- 支持ws/tcp/http……任何协议
- 高性能,添加数万条路由不会降低解析性能
- 路由分组、中间件...应有尽有
- ORM
- 支持数据库:mysql、clickHouse
- 关系处理:一对一、一对多、多对一、多态...有多种关系,可以跨数据库类型关联
- 缓存:自动刷新数据,支持配置各种缓存粒度
- 事件:所有操作都可以捕获,包括您使用原生SQL操作数据库
- 数据库连接:支持同步、异步、阻塞、断开和重新连接
- SQL模板:自动生成模板ID,您可以了解项目中有哪些类型的SQL,调用比例,并为后续数据优化提供数据支持。
- 语句重用:提供SQL执行性能
- 模型支持动态子数据库子表和大量数据
- RPC
- 可以自动生成远程方法映射,支持IDE提示
- 直接调用映射方法 == 调用远程方法,支持链式调用
- 支持
rpc middleware
,认证、加密和解密、缓存...
- 日志
- 完整信息:记录完整的文件名 + 行号,以便快速定位代码位置
- requestId:您可以轻松查看整个请求日志信息和服务关系
路由器
Router::get('/', \App\Controllers\IndexController::class . '@index'); // router with params Router::get('/user/{id}', \App\Controllers\IndexController::class . '@user'); // router with group Router::group(['namespace'=>'App\\Test\\WebSocket'],function (){ // websocket router Router::set('ws','/a','TestController@abc'); Router::set('ws','/b','TestController@bbb'); }); // Middleware Router::group([ 'middle' => [ \App\Test\MixPro\TestMiddle::class . '@checkSession' ] ], function () { Router::get('/mix/ws', HttpController::class . '@ws'); Router::get('/user/{id}', \App\Controllers\IndexController::class . '@user'); Router::post('/mix/http/send', HttpController::class . '@httpSend'); });
ORM
定义模型
namespace App\Model; use One\Database\Mysql\Model; // There is no need to specify the primary key in the model, the framework will cache the database structure // Automatically match the primary key, automatically filter the fields in the non-table structure class User extends Model { // Define the table name corresponding to the model CONST TABLE = 'users'; // define relationship public function articles() { return $this->hasMany('id',Article::class,'user_id'); } // define event // Whether to enable automatic caching // …… }
使用模型
- 数据库连接在
fpm
下是单列 - 所有数据库操作在
swoole
模式下自动切换到连接池
// Query a record $user = User::find(1); // Related query $user_list = User::whereIn('id',[1,2,3])->with('articles')->findAll()->toArray(); // update $r = $user->update(['name' => 'aaa']); // or $r = user::where('id',1)->update(['name' => 'aaa']); // $r To influence the number of records
缓存
// Set cache without expiration time Cache::set('ccc',1); // Set the cache to expire in 1 minute Cache::set('ccc',1,60); Cache::get('ccc'); // or cache ccc expires 10s under tag1 Cache::get('ccc',function (){ return 'info'; },10,['tag1']); // Refresh all caches under tag1 Cache::flush('tag1');
HTTP/TCP/WEBSOCKET/UDP
启动websocket服务器,添加http服务监控,添加tcp服务监控
[ // Main server 'server' => [ 'server_type' => \One\Swoole\OneServer::SWOOLE_WEBSOCKET_SERVER, 'port' => 8082, // Event callback 'action' => \One\Swoole\Server\WsServer::class, 'mode' => SWOOLE_PROCESS, 'sock_type' => SWOOLE_SOCK_TCP, 'ip' => '0.0.0.0', // swoole Server setting parameters 'set' => [ 'worker_num' => 5 ] ], // Add listener 'add_listener' => [ [ 'port' => 8081, // Event callback 'action' => \App\Server\AppHttpPort::class, 'type' => SWOOLE_SOCK_TCP, 'ip' => '0.0.0.0', // Set parameters for monitoring 'set' => [ 'open_http_protocol' => true, 'open_websocket_protocol' => false ] ], [ 'port' => 8083, // Unpacking protocol 'pack_protocol' => \One\Protocol\Text::class, // Event callback 'action' => \App\Test\MixPro\TcpPort::class, 'type' => SWOOLE_SOCK_TCP, 'ip' => '0.0.0.0', // Set parameters for monitoring 'set' => [ 'open_http_protocol' => false, 'open_websocket_protocol' => false ] ] ] ];
RPC
像调用本项目中的方法一样调用远程服务器的方法。跨语言,跨机器。
服务
启动rpc服务。框架为每种协议内置了rpc服务,只需在上面的配置文件中将它们添加到 action
中即可。例如:支持 http
调用,支持 tcp
调用。
// http Protocol rpc service [ 'port' => 8082, 'action' => \App\Server\RpcHttpPort::class, 'type' => SWOOLE_SOCK_TCP, 'ip' => '0.0.0.0', 'set' => [ 'open_http_protocol' => true, 'open_websocket_protocol' => false ] ], // tcp Protocol rpc service [ 'port' => 8083, 'action' => \App\Server\RpcTcpPort::class, 'type' => SWOOLE_SOCK_TCP, 'pack_protocol' => \One\Protocol\Frame::class, // tcp packing protocol 'ip' => '0.0.0.0', 'set' => [ 'open_http_protocol' => false, 'open_websocket_protocol' => false, 'open_length_check' => 1, 'package_length_func' => '\One\Protocol\Frame::length', 'package_body_offset' => \One\Protocol\Frame::HEAD_LEN, ] ]
将特定服务添加到rpc中,例如,有一个类Abc
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服务
// Add Abc to rpc service RpcServer::add(Abc::class); // If you don't want to add all the methods under Abc to the rpc service, you can also specify the addition. // Unspecified methods cannot be called by the client. // RpcServer::add(Abc::class,'add'); // Add in groups //RpcServer::group([ // // The middleware can do permission verification, data encryption and decryption, etc. // 'middle' => [ // TestMiddle::class . '@aa' // ], // // Cache If set, when called with the same parameters, the cache information will be returned and will not be called. Unit: seconds // 'cache' => 10 //], function () { // RpcServer::add(Abc::class); // RpcServer::add(User::class); //});
客户端调用
为了便于调用,我们创建了一个映射类(一个框架可以自动生成)
class ClientAbc extends RpcClientHttp { // rpc server address protected $_rpc_server = 'http://127.0.0.1:8082/'; // The remote class is not set and the default is the current class name protected $_remote_class_name = 'Abc'; }
调用rpc服务的远程方法与调用本项目的方法相同。你可以想象这个方法就在你的项目中。
$abc = new ClientAbc(5); // $res === 10 $res = $abc->add(2,3); // Chain call $res === 105 $res = $abc->setA(100)->add(2,3); // If the User of the above model is added to rpc // RpcServer::add(User::class); // The following operation results are the same as above // $user_list = User::whereIn('id',[1,2,3])->with('articles')->findAll()->toArray();
以上是通过http协议调用的。你也可以通过其他协议调用。例如,Tcp协议
class ClientAbc extends RpcClientTcp { // rpc server address protected $_rpc_server = 'tcp://127.0.0.1:8083/'; // The remote class is not set and the default is the current class name protected $_remote_class_name = 'Abc'; }
框架中有RpcClientHttp
和RpcClientTcp
类。你也可以将其复制到其他任何地方使用。
更多
文档
待办事项
- 支持Workerman
- ORM支持postgresql