dvaknheo/swoolehttpd

A Swoole Http Server in 2019

v1.0.4 2021-04-09 11:17 UTC

This package is auto-updated.

Last update: 2024-04-09 18:41:03 UTC


README

SwooleHttpd 是什么

SwooleHttpd 致力于 Swoole 代码和 fpm 平台 代码几乎不用修改就可以双平台运行。 是对 swoole_http_server 类的一个包裹。

SwooleHttpd 原先来自 PHP 框架 DuckPhp 的前身 DNMVCS。不对外引用其他 PHP 代码,简单可靠。 但是 SwooleHttpd 是设计成几乎和 DuckPhp 无关的Swoole 框架,所以我把他剥离了。

理论上应该是是高性能的

特色

直接使用超全局变量, 直接用 echo 输出。

最方便旧代码迁移。

当然, fpm 方式的代码还没那么简单就代替,我们动用 SwooleHttpd::GLOBALS() 代替全局变量 ,SwooleHttpd::STATICS()代替 静态变量 SwooleHttpd::CLASS_STATICS() 代替类内静态变量

还有对系统函数的封装 SwooleHttpd::header(),SwooleHttpd::setcookie() 等。

尤其是 session 方面的 SwooleHttpd::session_start() swoole_http_server 最常碰到的基本问题。

最后一个没法处理的: require ,include ,以及重复包含文件导致 函数的重复。

要处理这些,需要动用到 php-parser , 写个 SwooleHttpd::PHPFile(),或者 SwooleHttpd::require() SwooleHttpd::include() 想解决。不想折腾太大,所以没去折腾。

基本应用

使用方法:

composer require dvaknheo/swoolehttpd
<?php
use SwooleHttpd\SwooleHttpd;
require(__DIR__.'/../autoload.php');
function hello()
{
    echo "<h1> hello ,have a good start.</h1><pre>\n";
    var_export($_SERVER,$_GET,$POST,$_REQUEST,$_COOKIE, $_SESSION);
    echo "</pre>";
    return true;
}

$options=[
    'port'=>9528,
    'http_handler'=>'hello',
];
SwooleHttpd::RunQuickly($options);

浏览器打开 http://127.0.0.1:9528/ 这个例子展现了 $_SERVER 里有的东西

选项

RunQuickly 的 默认选项 $$options SwooleHttpd::DEFAULT_OPTIONS 有

const DEFAULT_OPTIONS=[
        'swoole_server'=>null,          // swoole_http_server 对象,留空,则用 host,port 创建
        'swoole_options'=>[],           // swoole_http_server 的配置,合并入 swoole_server
        
        'host'=>'0.0.0.0',              // IP
        'port'=>0,                      // 端口
        
        'http_handler'=>null,           // 启动方法,返回 false 表示 404
        'http_handler_basepath'=>'',    // 基础目录目录 ,搭配用于配置 http_handler_root ,http_handler_file
        'http_handler_root'=>'',        // PHP 目录模式。
        'http_handler_file'=>'',        // 映射所有 URI 到单一文件模式
        'http_exception_handler'=>null, // 异常处理回调, set_exception_handler 会覆盖这个配置
        'http_404_handler'=>null,       // 404 的处理回调

        'with_http_handler_root'=>false,// 复用 http_handler_root 404 后会从目录里载入
        'with_http_handler_file'=>false,// 复用 http_handler_root 404 后会从文件里载入

        'enable_fix_index'=>true,       // http_handler 模式下,修正 index.php 为空
        'enable_path_info'=>true,       // http_handler_root 允许 path_info
        'enable_not_php_file'=>true,    // http_handler_root 允许包含资源文件
        
        'base_class'=>null,             // 替换 SwooleHttpd 类初始化
        'silent_mode'=>false,           // 安静模式,不在命令行中提示服务启动信息。
        'enable_coroutine'=>true,       // 启用 \Swoole\Runtime::enableCoroutine();
];

难度级别

从难度低到高,大概是这样的级别以实现目的

  1. 使用默认选项实现目的
  2. 只改选项实现目的
  3. 调用 SwooleHttpd 类的静态方法实现目的
  4. 调用 SwooleHttpd 类的动态方法实现目的
  5. ---- 初级程序员和高级程序员分界线 ----
  6. 使用入口类扩展
  7. 调用扩展类,组件类的动态方法实现目的
  8. 继承接管特定类实现目的
  9. 魔改,硬改 SwooleHttpd 的代码实现目的

三种模式

SwooleHttpd 有三种模式

  1. http_handler

    主要模式 所有url请求都到这个回调处理。 这模式和后面两种模式的区别,就是不搜索文件 with_http_handler_root 打开时,http_handler 返回 false 后继续进入 http_handler 搜索文件运行

  2. http_handler_root

    这和 document_root 一样。读取php文件,然后运行的模式。 注意重复包含类会导致异常. with_http_handler_file 打开时 找不到文件会进入 http_handler_file 处理。 enable_not_php_file 允许读取资源文件,如图片,将会在浏览器显示图片。

  3. http_handler_file

    这种模式是把 url 都转向 文件如 index.php 来处理。

常用静态方法

常用静态方法,基本都要用到的静态方法

RunQuickly(array $options=[],callable $after_init=null)

入口,等价于 SwooleHttpd::G()->init($options)->run();
如果 after_init不为 null 将会在 init 后执行

ThrowOn($flag,$message,$code=0)

如果 flag 成立抛出异常
和 DuckPhp 不同的是,这里抛出 SwooleException。

Server()

获得当前 swoole_server 对象

Request()

获得当前 swoole_request 对象
返回 SwooleContext::G()->request

Response()

获得当前 swoole_response 对象
返回 SwooleContext::G()->response

OnShow404()

处理404的通用方法,选项 http_404_handler 优先使用

OnException($ex)

异常的处理方法,选项 http_exception_handler 优先使用

超全局变量静态方法

代替超全局变量,基本由 SwooleSuperGlobal 的动态方法实现 高级程序员可以由接管 SwooleSuperGlobal 以实现自己的解决方式。

&GLOBALS($k,$v=null)

全局变量 global 语法的替代方法
返回 SwooleSuperGlobal::G()->STATICS($k,$v)

&STATICS($k,$v=null)

静态变量 static 语法的替代方法
返回 SwooleSuperGlobal::G()->_STATICS($k,$v)

&CLASS_STATICS($class_name,$var_name)

类内静态变量 static 语法的替代方法
$class_name 传入类名,以确定是 self::class 还是 static::class
返回 SwooleSuperGlobal::G()->_CLASS_STATICS($class_name,$var_name)

系统封装静态方法

对应PHP手册的函数的全局函数的替代,因为相应的同名函数在 Swoole环境下不可用。 特殊函数 system_wrapper_get_providers 介绍了有多少系统替换函数。 所有这些静态方法都是调用动态方法实现,以方便修改。

system_wrapper_get_providers()

特殊方法,对外提供本类有的系统封装函数

exit($code=0)

特殊方法,对应  exit() 语法。退出系统,swoole 里,直接 exit 也是可以的。

header(string $string, bool $replace = true , int $http_status_code=0)

header 函数

setcookie(string $key, string $value = '', int $expire = 0 , string $path = '/', string $domain = '', bool $secure = false , bool $httponly = false)

设置 cookie

set_exception_handler(callable $exception_handler)

设置异常函数

register_shutdown_function(callable $callback,...$args)

退出关闭函数

session_start(array $options=[])

开始 session

session_destroy()

结束 session

session_set_save_handler(\SessionHandlerInterface $handler)

设置 session_handler

WebSocket 服务器方法

Frame Fd IsClosing

高级静态方法

这些静态方法,初学者可以忽略

static G($object=null)

G 函数,可替换单例。

ReplaceDefaultSingletonHandler()

替换单例实现
实质返回 SwooleCoroutineSingleton::ReplaceDefaultSingletonHandler();

EnableCurrentCoSingleton()

开启协程内单例,比如 \go 函数里你需要用到自己的协程单例。
实质返回 SwooleCoroutineSingleton::EnableCurrentCoSingleton();

单例模式

SwooleHttpd use trait SingletonEx 。 SingletonEx 定义了静态函数 G($object=null) ,如果默认参数的话得到当前单例。 如果传入 $object 则替换单例,实现调用方式不变,实现方式改变的效果。

SwooleHttpd:: 通过使用 SwooleCoroutineSingleton 进一步扩展了 SingletonExTrait ( 通过 __SINGLETONEX_REPALACER 宏 ) 实现了协程内单例。

如果协程内没单例,会查找全局的单例($cid=0)的

在协程结束时候,会自动清理所有协程单例。

超全局变量和语法代替静态方法

swoole 的协程使得 跨领域的 global ,static, 类内 static 变量不可用, 我们用替代方法

<?php
use DuckPhp\SwooleHttpd as DN;
require (__DIR__.'/../autoload.php');

global $n;
// =>
$n=&DN::GLOBALS('n');

static $n;
// =>
$n=&DN::STATICS('n');  //别漏掉了 &

$n++;
var_dump($n);

class B
{
    protected static $var=10;
    public static function foo()
    {
        //static::$var++;
        //var_dump(static::$var);
        $_=&DN::CLASS_STATICS(static::class,'var');$_   ++;
        // 把 static::$var 替换成  $_=&DN::CLASS_STATICS(static::class,'var');$_
        //别漏掉了 &
        var_dump(DN::CLASS_STATICS(static::class,'var')); // 没等号或 ++ -- 之类非左值不用 &
    }
}
class C extends B
{
    protected static $var=100;
}
C::foo();C::foo();C::foo();

输出

int(1)
int(101)
int(102)
int(103)

高级内容

前面是使用者知道就够的内容,后面是高级内容了

SwooleHttpd 的其他对外动态方法

init($options=[])

初始化,这是最经常子类化完成自己功能的方法。
你可以扩展这个类,添加工程里的其他初始化。

run()

运行,运行后进入 swoole_http_server

set_http_exception_handler($ex)

设置异常

exit_request($code=0)

退出当前请求,等同于 exit

getDynamicClasses()

获取动态类 http_handler 模式

forkMasterInstances($classes,$exclude_classes=[])

把master 实例clone 到当前协程。exclude_classes 表示,如果是 克隆的实例有当前的类,则跳过不克隆

resetInstances()

重置 协程为0 的实例覆盖到当前协程,用空的实例,而不是原有实例。

简单 HTTP 服务器

SwooleHttpd 用的 trait SwooleHttpd_SimpleHttpd . 单独使用这个 trait 你可以实现一个 http 服务器

protected function onHttpRun($request,$response){}
protected function onHttpException($ex){}
protected function onHttpClean(){}
public function onRequest($request,$response)
初始化 SwooleContext 和一些处理。

协程单例方法

不常用方法,主要提供给 init 前调用

getDymicClasses()
createCoInstance($class,$object)
forkMasterInstances($classes,$exclude_classes=[])
resetInstances()

SwooleException extends \Exception

空类,异常类

Swoole404Exception extends \Exception

空类,404 异常

SwooleSingleton

共享 trait

SwooleHttpd 重写了 可变单例 G 函数的实现,使得做到协程单例。

class SwooleCoroutineSingleton

用于协程单例,把主进程单例复制到协程单例
public static function ReplaceDefaultSingletonHandler() //替换默认Handler
public static function SingletonInstance($class,$object) // handelr 实现
public static function GetInstance($cid,$class)
public static function SetInstance($cid,$class,$object)
public static function DumpString()  // 打印
public function cleanUp()
public function forkMasterInstances($classes,$exclude_classes=[]) //把主协程的实例扩充到协程
public function forkAllMasterClasses() // 主协程的 G 都扩充到 协程, 和上面例子不同的是...
public function _DumpString()
public static function Dump() 

class SwooleContext

协程单例。Swoole 的运行信息
public function initHttp($request,$response)
public function initWebSocket($frame)
public function cleanUp()
public function onShutdown()
public function regShutDown($call_data)
public function isWebSocketClosing()

class SwooleSuperGlobal

SwooleSuperGlobal 是 Swoole 下 超全局变量 的实现。
同时处理 session
调用 SwooleSessionHandler ,
public $is_inited=false;
public function init()
public function &_GLOBALS($k, $v=null)
public function &_STATICS($name, $value=null, $parent=0)
public function &_CLASS_STATICS($class_name, $var_name)
public function session_set_save_handler($handler)
public function session_start(array $options=[])
public function session_id($session_id=null)
public function session_destroy()
public function writeClose()
public function create_sid()

SwooleSessionHandler implements \SessionHandlerInterface

因为默认的 SessionHandler 不能直接用,这里做文件实现版本的 SessionHandler 。

如果你有自己的 SessionHandler ,用 SwooleHttpd::session_set_save_handler() 安装;

代码解读

基本流程 init()

开始检测是否有 base_class ,如果有,则替换当前单例为 base_class 的实现,
返回 base_class 的 G 实例的 init

载入选项 如果没有 server 对象则根据配置创建一个。

SwooleCoroutineSingleton::ReplaceDefaultSingletonHandler(); 替换单例
宏 DuckPhp_SUPER_GLOBAL_REPALACER 定为 SwooleSuperGlobal::G
宏 DuckPhp_SYSTEM_WRAPPER_INSTALLER 定为 static::system_wrapper_get_providers;

基本流程 run()

如果不是安静模式,则打印相关信息
$this->server->start();

基本流程 onRequest()

onRequest 实现于 trait SwooleHttpd_SimpleHttpd
trait SwooleHttpd_SimpleHttpd (估计现实也没人会用到 SwooleHttpd_SimpleHttpd 而不用 SwooleHttpd )
一开始就 defer 手动 gc
SwooleCoroutineSingleton::EnableCurrentCoSingleton 开启 onRequest 协程的协程单例

defer 配合 ob_start 处理直接 echo 输出

SwooleContext 初始化
SwooleSuperGlobal::G 初始化

注意代码 SwooleSuperGlobal::G(new SwooleSuperGlobal());
为什么不是 SwooleSuperGlobal::G();
因为要确保 SwooleSuperGlobal::G() 得到的单例是 协程内的单例。

接下来 正常流程  onHttpRun 处理 http 业务
出异常则 onHttpException  处理异常。

流程结束后,进入前面 defer 流程里处理善后
包括 伪 regist_shutdown_function  处理
其他信息则  onHttpClean 处理
SwooleContext 善后处理
关闭 response;
(这个 defer 折腾了一段时间处理顺序,没 bug 就暂时不要动了。)

基本流程 onHttpClean()

SwooleHttpd onHttpClean
处理 autoload ,防止 http_handler_root/http_handler_file 模式多次载入 spl_autoload

基本流程 onHttpException($ex)

这个很简单
如果是 \Swoole\ExitException 异常, 不用处理
如果是  Swoole404Exception 则 static::OnShow404();
否则 static::OnException($ex);

基本流程 onHttpRun

主要流程。
保存 spl_autoload_functions

如果 http_handler 模式

关闭自动清理 autoload
处理选项  enable_fix_index
运行 http_handler
如果得到的是 false 而且非 with_http_handler_root,非 http_handler_file 则404
否则打开自动清理 autoload,继续

如果 http_handler_root 模式

如果 http_handler_file 模式

DuckPhp handler 相关。

WebSocket(测试中)

配置

        //* websocket 在测试中。未稳定
        'websocket_open_handler'=>null,     // websocket 打开
        'websocket_handler'=>null,          // websocket  处理
        'websocket_exception_handler'=>null,// websocket 异常处理
        'websocket_close_handler'=>null,    // websocket 关闭

静态方法

Frame()

获得当前 frame (websocket 生效 )  

FD()

获得当前 fd  (websocket 生效)

IsClosing()

判断是否是关闭的包 (websocket 生效)

简单 websocket 服务器

SwooleHttpd 用的 trait SwooleHttpd_WebSocket . 单独使用这个 trait 你可以实现一个 websocket 服务器

onRequest($request,$response)

//

onOpen(swoole_websocket_server $server, swoole_http_request $request)

//

onMessage($server,$frame)

//

没有 OnClose 。