swoft 假的最佳实践

这是一篇使用swoft两个月后的总结文章!,后续会陆续更新的

这是web-api开发的总结,如果使用websocket等服务的可能不适用,本章节会对一些规范、习惯,或者优化进行一些说明

一. 安装 & 环境

swoole 安装

swoft开发的环境最好是mac(以下截图都是以mac环境下的)

以下安装代码是需要开启 openssl 扩展的,如果不需要可以直接 pecl install swoole 一路回车即可

$ brew info openssl
--------------------
For compilers to find openssl you may need to set:
  export LDFLAGS="-L/usr/local/opt/openssl/lib"
  export CPPFLAGS="-I/usr/local/opt/openssl/include”
* * * * *
复制 /usr/local/opt/openssl
$  pecl install swoole
* * * * *
enable openssl support? [no] : yes --with-openssl-dir=/usr/local/opt/openssl

新手必备扩展

sdebug,兼容swoole的xdebug分支(https://github.com/mabu233/sdebug

swoft因为文档不够详细,有时候必须看源码,跟踪运行,断点调试必不可少

composer扩展
  1. swoft/devtool(用于数据库迁移,实体生成)
  2. ctfang/swoft-admin(devtool无界面过度库,开发界面操作,日记查看、在线代码查看、路由生成、控制器生成等等)

Swoft 安装无特别,跳过

composer create-project swoft/swoft swoft

二. 配置修改,常用环境.env配置新增

  1. HTTP_PORT http服务端口
  2. DB_DSN 数据库dns
  3. DB_USERNAME 数据库用户名
  4. DB_PASSWORD 数据库用户密码

.env 文件是不提交到git的,所以不会产生冲突,团队每个人都新增一份,.env所有键值对都应该在.env.example存在一份默认值和注释说明。

使用 .env里的配置,在app/bean.php文件下使用 'port' => env("HTTP_PORT",18306),,当然env()函数是不限制在配置文件用的,只是一般为了业务扩展,习惯在配置使用而已。

三. 重要目录划分

app/Common

对项目内部,公用的、公开的。

定义一个接口返回格式类

<?php

namespace App\Common;

class Message
{
    const EROR = 100;

    public static function ok():array
    {
        return ['code' => 0, 'msg' => "ok", 'data' => null];
    }

    public static function success($data = []):array
    {
        return ['code' => 0, 'msg' => 'ok', 'data' => $data];
    }

    public static function code(array $msg)
    {
        return ['code' => $msg[0], 'msg' => $msg[1], 'data' => null];
    }

    public static function error($msg = 'error', $code = self::EROR, $data = [])
    {
        return ['code' => $code, 'msg' => $msg, 'data' => $data];
    }
}

定义一个状态码类

<?php

namespace App\Common;

/**
 * 状态码定义
 * @package App\Common
 */
class Code
{
    public const Ok = [0, "ok"];
    public const Unknown = [1, "未知错误"];
    public const NotUsers = [2, "用户不存在"];
}

这样,所有接口都可以使用 Message::code(Code::NotUsers)Message::success(['time'=>time()])

app/Model/Dao

项目内部数据库操作类。例如用户操作curd就可以定一个UserDao

app/Model/Data

跨模块数据定义,有一点像数据缓存层,但是Data不是用于放跨多起请求有效的缓存,例如session for redis就不适用了,但是从redis取出来的session数据后,转化成SessionData就可以放到Data目录,因为SessionData对象是当前请求有效的。

app/Model/Service

外部项目和内部项目的对接层,也可以有小部分业务处理;例如:
定义一个苹果支付AppStoreService,那么它和苹果支付服务对接的。
定义一个支付服务 PayService,它是用户初始化支付库的配置的(目前推荐 yurunsoft/pay-sdk,吐槽下这个库不是psr编码规范,强迫症要犯了)

app/Model/Entity

数据库实体,由 Devtool 生成,没有必要手动修改

app/Model/Logic

逻辑层,范围很广,上面Model不好分层的时候,就放到这里好了,所有代码都是有逻辑的……

四. 中间件

swoft不支持路由分组,所以只能判断路由,录入定义一个登录权限检查,因为少数一两个接口不用检查,只能声明一个全局中间件,再在中间内部判断如果是公开路由,就跳过

        // 对外公开的接口
        $path = $request->getUri()->getPath();
        if (in_array($path, self::$publicAction)) {
            $response = $handler->handle($request);
            return $response;
        }

往请求赋值

像用uid等,因为所有接口都可以使用的,就是需要在中间件可以检查出来,可以直接赋值到请求对象

$request->uid = $token->uid;

如果某个请求使用的值,可以使用psr规范的 withAttribute

$request = $request->withAttribute('test','这是值')

如果你是新项目,可以使用 ctfang/swoft-admin 创建控制器,在创建控制器时候选择启用的中间件,这样就不会漏
新增控制器

五. 调试

断点调试

如果有安装 sdebug 扩展,需要停止 php-fpm 服务,默认端口冲突,不然不能使用。

新增 phpStorm 断点启动,
swoft假的最佳实践

在代码新增断点,在代码左侧行数旁边,鼠标点击,就可以新增

swoft假的最佳实践

启动断点,点击小虫子图标

swoft假的最佳实践

请求来到断点时候,就会自动停止,等待你点击下一步才可以继续运行

Sql调试

修改 app/Listener/RanListener.php,取消注释 output()->info($rawSql);,就会把所有sql打印到控制器。
如果线上的测试环境,可以新增 Log::debug($rawSql); ,把sql写到独立一个文件里,然后使用 ctfang/swoft-admin在线查看日记。

swoft假的最佳实践

注意使用 ctfang/swoft-admin,一定设置内网访问,因为它权限非常大,可以直接查看代码和执行命令等。

swoft假的最佳实践

六. 内存优化

因为常驻内存,所有内存都是敏感的,不像fpm,请求结束直接回收。常驻内存后,哪怕是临时对象,也要等缓冲区满了,php才收拾垃圾的,能省一点是一点。

  • 所有数据对象化
  • 例如像导出excel文档等,最好也是定义一个类文件进行赋值:

uid username
1 张三

可以定义一个类

class UserExcelData {
  public $uid;
  public $username;
}

赋值就可以节省 key 带来的消耗,对象赋值只是简单的属性地址赋值,key本身字符串是省去的。
数据大时候,节省的内存非常可观,对比数组赋值,几十倍都有可能。

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
讨论数量: 7
Inhere

:+1:

4年前 评论
AB (楼主) 4年前
Yurun

你吐槽yurunsoft/pay-sdk被我发现了 :joy:。。。其实 psr 只是一种规范,可以遵守,但没必要。。。我个人觉得 psr 全家桶里有很多不合理的东西

4年前 评论
AB (楼主) 4年前
李铭昕 4年前
Yurun (作者) 4年前

大佬牛逼(破音)!!!!!!

4年前 评论

请问大佬sdebug是啥,一直都用xdebug,但swoole拓展不兼容xdebug,上面用的sdebug能不能科普一下,搜了一下也没有搜到 :sweat_smile:

4年前 评论
AB (楼主) 4年前
man (作者) 4年前

有个不懂的地方,文章最后说:
“赋值就可以节省 key 带来的消耗,对象赋值只是简单的属性地址赋值,key 本身字符串是省去的。
数据大时候,节省的内存非常可观,对比数组赋值,几十倍都有可能。”

这里指的对象赋值,是在导出excel时将数据赋值到类 然后给到 excel对象吗?
想看看一个代码例子请教一下~

4年前 评论
AB (楼主) 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!