一个极简高性能php框架,支持[swoole | php-fpm ]环境

Overview

One - 一个极简高性能php框架,支持[swoole | php-fpm ]环境

  • 快 - 即使在php-fpm下也能1ms内响应请求
  • 简单 - 让你重点关心用one做什么,而不是怎么用one
  • 灵活 - 各个组件松耦合,可以灵活搭配使用,使用方法保持一致
    • 原生sql可以和模型关系with搭配使用,关系可以跨数据库类型
    • session 可以在http,websocket甚至tcp,udp和cli下使用
    • ...
  • 高效 - 运行性能,开发效率,易维护。
  • 轻量 - 无其他依赖,从路由、orm所有组件代码量一共不超过500k,若二次开发没有复杂的调用关系,可快速掌握设计原理

QQ交流群:731475644

珍爱生命,抵制996 LICENSE

hello world

安装

composer create-project lizhichao/one-app app
cd app
php App/swoole.php 

# 停止 : `php App/swoole.php -o stop`  
# 重启 : `php App/swoole.php -o reload`  
# 守护进程启动 : `php App/swoole.php -o start`  

curl http://127.0.0.1:8081/

性能

参考:

主要组件

  • 路由

    • 支持贪婪匹配和优先级
    • 支持ws/tcp/http……任意协议
    • 性能好,添加几万条路由也不会降低解析性能
    • 路由分组,中间件……该有的都有
  • ORM模型

    • 支持数据库:mysql,clickHouse,
    • 关系处理:一对一,一对多,多对一,多态…… 各种关系的都有,可以跨数据库类型关联
    • 缓存:自动刷新数据 支持配置各种缓存粒度
    • 事件:所有操作都能捕获 包括你用原生sql操作数据库
    • 数据库连接:同步、异步、阻塞、断线重连都支持
    • sql模板: 自动生成模板id,可了解项目有哪些类型sql,以及调用次数占比情况,对后期数据优化提供数据支持。
    • statement复用:提供sql执行性能
  • rpc

    • 可自动生成远程方法映射,支持ide提示
    • 直接调用映射方法 == 调用远程方法,支持链式调用
    • 支持rpc中间件,鉴权、加解密、缓存……
  • 日志

    • 信息完整:记录完整的文件名+行号可快速定位代码位置
    • requestId:可轻松查看整个请求日志信息和服务关系
  • ...

    • QQ交流群: 731475644

路由

Router::get('/', \App\Controllers\IndexController::class . '@index');

// 带参数路由
Router::get('/user/{id}', \App\Controllers\IndexController::class . '@user');

// 路由分组 
Router::group(['namespace'=>'App\\Test\\WebSocket'],function (){
	// 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('/user/{id}', \App\Controllers\IndexController::class . '@user');
    Router::post('/mix/http/send', HttpController::class . '@httpSend');
});

orm 模型

定义模型

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模式下所有数据库操作自动切换为连接池
// 查询一条记录
$user = User::find(1);

// 关联查询
$user_list = User::whereIn('id',[1,2,3])->with('articles')->findAll()->toArray();

// 更新
$r = $user->update(['name' => 'aaa']);
// 或者
$r = user::where('id',1)->update(['name' => 'aaa']);
// $r 为影响记录数量

缓存

// 设置缓存 无过期时间
Cache::set('ccc',1);

// 设置缓存 1分钟过期
Cache::set('ccc',1,60);

// 获取
Cache::get('ccc');

// 或者 缓存ccc 过期10s 在tag1下面
Cache::get('ccc',function (){
    return '缓存的信息';
},10,['tag1']);

// 刷新tag1下的所有缓存
Cache::flush('tag1');

HTTP/TCP/WEBSOCKET/UDP服务器

启动一个websocket服务器, 添加http服务监听, 添加tcp服务监听

[
	 // 主服务器
    '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

像调用本项目的方法一样调用远程服务器的方法。跨语言,跨机器。

服务端

启动rpc服务,框架已经内置了各个协议的rpc服务,添加到到上面配置文件的action即可。列如: 支持http调用,又支持tcp调用。

// http 协议 rpc服务
[
    '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 协议 rpc服务
[
    'port'          => 8083,
    'action'        => \App\Server\RpcTcpPort::class,
    'type'          => SWOOLE_SOCK_TCP,
    'pack_protocol' => \One\Protocol\Frame::class, // tcp 打包 解包协议
    '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服务

// 添加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框架可自动生成)

class ClientAbc extends RpcClientHttp {

    // rpc服务器地址
    protected $_rpc_server = 'http://127.0.0.1:8082/';

    // 远程的类 不设置 默认为当前类名
    protected $_remote_class_name = 'Abc';
}

调用rpc服务的远程方法, 和调用本项目的方法一样的。你可以想象这个方法就在你的项目里面。

$abc = new ClientAbc(5);

// $res === 10
$res = $abc->add(2,3);

// 链式调用 $res === 105
$res = $abc->setA(100)->add(2,3);

// 如果把上面的模型的User添加到rpc
// RpcServer::add(User::class);
// 下面运行结果和上面一样
// $user_list = User::whereIn('id',[1,2,3])->with('articles')->findAll()->toArray();

上面是通过http协议调用的。你也可以通过其他协议调用。例如Tcp协议

class ClientAbc extends RpcClientTcp {

    // rpc服务器地址
    protected $_rpc_server = 'tcp://127.0.0.1:8083/';

    // 远程的类 不设置 默认为当前类名
    protected $_remote_class_name = 'Abc';
}

其中类 RpcClientHttp,RpcClientTcp在框架里。
你也可以复制到任何其他地方使用。

更多

文档

TODO

QQ交流群: 731475644

我的其他开源项目

You might also like...
Socks5 proxy server written in Swoole PHP

php-socks This is a Socks5 proxy server implementation built with PHP & Swoole. To start the proxy server, clone this repo, run composer install to in

DoraRPC is an RPC For the PHP MicroService by The Swoole

Dora RPC 简介(Introduction) Dora RPC 是一款基础于Swoole定长包头通讯协议的最精简的RPC, 用于复杂项目前后端分离,分离后项目都通过API工作可更好的跟踪、升级、维护及管理。 问题提交: Issue For complex projects separation

PHP Coroutine HTTP client - Swoole Humanization Library

PHP Coroutine HTTP client - Swoole Humanization Library

基于 swoole 的多进程队列系统,低延时(最低毫秒级)、低资源占用, 支持一键化协程、超时控制、失败重试。可与 laravel thinkphp 等框架配合使用
基于 swoole 的多进程队列系统,低延时(最低毫秒级)、低资源占用, 支持一键化协程、超时控制、失败重试。可与 laravel thinkphp 等框架配合使用

multi-process-queue 基于swoole的多进程队列系统,manage进程管理子进程,master进程监听队列分发任务,worker进程执行任务, 多进程、低延时(最低毫秒级)、低资源占用。可与 laravel thinkphp 等框架配合使用 版本要求: php=7.1 swoo

swoole worker
swoole worker

SwooleWorker SwooleWorker is a distributed long connection development framework based on Swoole4. 【Github】 【HomePage】 Manual 【ENGLISH】 【简体中文】 Usage s

Library for Open Swoole extension

Open Swoole Library This library works with Open Swoole since release version v4.7.1. WIP Table of Contents How to Contribute Code Requirements Develo

Hyperf instant messaging program based on swoole framework
Hyperf instant messaging program based on swoole framework

Hyperf instant messaging program based on swoole framework

LaravelS is an out-of-the-box adapter between Swoole and Laravel/Lumen.
LaravelS is an out-of-the-box adapter between Swoole and Laravel/Lumen.

🚀 LaravelS is an out-of-the-box adapter between Swoole and Laravel/Lumen.

Hprose asynchronous client & standalone server based on swoole
Hprose asynchronous client & standalone server based on swoole

Hprose for Swoole Introduction Hprose is a High Performance Remote Object Service Engine. It is a modern, lightweight, cross-language, cross-platform,

Comments
  • Breaking change detected in patch level

    Breaking change detected in patch level

    Hi @lizhichao,

    I can see that this dependency has been introduce in 2.0.23, but was not in 2.0.22 https://github.com/lizhichao/one/blob/8ab51aec0ce645c1f952b5628e56e800999437cc/composer.json#L22

    This mean bcmath is now required. As I have not this extension, this break my CI (hopefully it is not a production).

    BTW, I have fixed this in https://github.com/the-benchmarker/web-frameworks/pull/3632

    Regards,

    opened by waghanza 5
  • 在swoole环境下error_get_last这种错误不会直接输出

    在swoole环境下error_get_last这种错误不会直接输出

    测试例子,IndexContoller需要extends Controller,我在测试时use One\Http\Controller;这个路径写错了,虽然这个是个人的失误,但出错后,postman下调试页面一直显示是空的,看不出问题,后来看了下cli下的报错才发现问题,能否让这个报错信息直接输出在页面中,例如:{ "err": 500, "rid": "5f3f93f8303b7227e468a902e821623f", "msg": "xxx", "res": "" }这样比较直观,因为不会一直注意到控制台上的信息.fpm模式下是没有问题,错误会正常输出.

    opened by xilin693 3
  • 框架有没有封装退出的方法,用于调试的

    框架有没有封装退出的方法,用于调试的

    比如说我需要在确认代码在运行到某个位置是否正常 ,我可能会var_dump($param)或echo $param然后执行exit. swoole不支持exit,所以我现在使用的是throw new \Exception($param)的方式来调试,这样one框架有返回一个500的json,里边可以看到$param的信息,有没有更好的方法

    opened by xilin693 2
  • 建议添加热重启

    建议添加热重启

    首先在protocol.php配置加上

    'monitor' => [
                'timer' => 2000,  //定时器间隔时间,单位毫秒
                'debug' => true,       //重启
                'path' => [
                    _APP_PATH_
                ]
            ],
    
    

    其次找到 vendor/lizhichao/one/src/Swoole/Server.php 修改onWorkerStart方法,加上

      $this->lastMtime = time();
      if (0 == $worker_id) {
                $this->monitor($server);
       }
    

    接着加上monitor方法

      protected function monitor(\swoole_server $server)
        {
            $monitor = $this->conf['monitor'];
            $paths = $monitor['path'];
            $timer = $monitor['timer'] ?: 2;
    
            $server->tick($timer, function () use ($paths, $server) {
                foreach ($paths as $path) {
                    $dir = new \RecursiveDirectoryIterator($path);
                    $iterator = new \RecursiveIteratorIterator($dir);
    
                    foreach ($iterator as $file) {
                        if (pathinfo($file, PATHINFO_EXTENSION) != 'php') {
                            continue;
                        }
    
                        if ($this->lastMtime < $file->getMTime()) {
                            $this->lastMtime = $file->getMTime();
                            echo '[update]' . $file . " reload...\n";
                            $server->reload();
                            return;
                        }
                    }
                }
            });
        }
        
    

    这样只要App目录下,有代码修改,在监控为debug=true时候,会自动重启,不必每次手动重启

    opened by yumufeng 1
Owner
vic
大道至简
vic
☄️ PHP CLI mode development framework, supports Swoole, WorkerMan, FPM, CLI-Serve

☄️ PHP CLI mode development framework, supports Swoole, WorkerMan, FPM, CLI-Server / PHP 命令行模式开发框架,支持 Swoole、WorkerMan、FPM、CLI-Server

Mix PHP 1.8k Dec 29, 2022
💫 Vega is a CLI mode HTTP web framework written in PHP support Swoole, WorkerMan / Vega 是一个用 PHP 编写的 CLI 模式 HTTP 网络框架,支持 Swoole、WorkerMan

Mix Vega 中文 | English Vega is a CLI mode HTTP web framework written in PHP support Swoole, WorkerMan Vega 是一个用 PHP 编写的 CLI 模式 HTTP 网络框架,支持 Swoole、Work

Mix PHP 46 Apr 28, 2022
Multi-process coroutine edition Swoole spider !! Learn about Swoole's network programming and the use of its related APIs

swoole_spider php bin/spider // Just do it !! Cache use Swoole\Table; use App\Table\Cache; $table = new Table(1<<20); // capacity size $table->column

null 3 Apr 22, 2021
A easy way to install your basic yii projetc, we have encrypt database password in phpfile, my class with alot funtions to help you encrypt and decrypt and our swoole server install just run ./yii swoole/start and be happy!

Yii 2 Basic Project Template with swoole and Modules Yii 2 Basic Project Template is a skeleton Yii 2 application best for rapidly creating small proj

null 3 Apr 11, 2022
swoole,easyswoole,swoole framework

EasySwoole - A High Performance Swoole Framework EasySwoole is a distributed, persistent memory PHP framework based on the Swoole extension. It was cr

null 4.6k Jan 2, 2023
swoole and golang ipc, use goroutine complete swoole coroutine

swoole and golang ipc demo swoole process module exec go excutable file as sider car, use goroutine complete swoole coroutine hub.php <?php require '

null 2 Apr 17, 2022
球球大作战(PHP+Swoole)

球球大作战 在线多人H5游戏(H5客户端, 服务端) W A S D 控制 技术栈: PHP7.4+ Swoole4.6(多进程, WebSocket, 共享内存) SpriteJS v3(2D Canvas渲染) 演示Demo 安装: 环境要求:Linux,PHP7.4+(启用Swoole拓展)

Vacant 15 May 9, 2022
🚀 Developing Rocketseat's Next Level Week (NLW#05) Application using PHP/Swoole + Hyperf

Inmana PHP ?? Developing Rocketseat 's Next Level Week (NLW#05) Application using Swoole + Hyperf. This is the app of the Elixir track. I know PHP/Swo

Leo Cavalcante 18 Jun 1, 2022
Simple live support server with PHP Swoole Websocket and Telegram API

Telgraf Simple live support server with PHP Swoole Websocket and Telegram API. Usage Server Setup Clone repository with following command. git clone h

Adem Ali Durmuş 6 Dec 30, 2022
Redis watcher for PHP-Casbin in Swoole.

Redis watcher for PHP-Casbin in Swoole Redis watcher for PHP-Casbin in Swoole , Casbin is a powerful and efficient open-source access control library.

PHP-Casbin 1 Nov 22, 2021