高性能PHP框架 webman 开发规范1.0

未知
2025-02-20 11:00:49
0

高性能PHP框架 webman 开发规范1.0

总结下webman最新版本的开发规范以及代码建议。欢迎大家提交自己更好的开发规范以及代码建议。

PHP版本选择

如果是一个全新项目,并没有PHP版本依赖,目前应该尽量选择PHP8.2+作为你的PHP版本,可以拥有更好的性能,webman1.6.0最新版本的最低版本要求是PHP8.0

1.6.0升级指南:https://www.workerman.net/doc/webman/upgrade/1-6.html

有些PHP扩展可能不支持PHP的高版本,这个时候你要做出选择,使用低版本还是寻求更好的扩展解决方案。

基本命名规范

webman遵循PSR-2命名规范以及PSR-4自动加载规范,并注意如下规范:

如果你没有遵循某些规范,可能会导致部分功能的异常。

类和文件命名

  • 类(包括接口、Trait)文件名和类名保持一致,并且使用首字母大写的驼峰命名;
  • 函数文件、配置文件、路由定义文件等文件名使用小写规范;
  • 无论类还是普通文件都使用.php后缀;
  • 目录名统一使用小写规范,并且使用单数规范;
  • 模板文件使用小写规范;

配置和变量命名

  • 配置参数名统一使用小写规范;
  • 常量定义统一使用大写规范;
  • 环境变量定义统一使用大写规范;

函数和类、属性命名

  • 函数的命名使用小写字母和下划线(小写字母开头)的方式,例如generate_order_no
  • 方法的命名使用驼峰法(首字母小写),例如getUserName
  • 属性的命名使用驼峰法(首字母小写),例如tableNameinstance
  • 特例:以双下划线__打头的函数或方法作为魔术方法,例如__call__callStatic

常驻内存

webman是常驻内存的框架,一般来说,php文件载入后便以opcode的方式常驻内存,不会再次从磁盘读取(模版文件除外)。  所以正式环境业务代码或配置变更后需要执行php start.php reload才能生效。如果是更改进程相关配置或者安装了新的composer包需要重启php start.php restart

为了方便开发,webman自带一个monitor自定义进程用于监控业务文件更新,当有业务文件更新时会自动执行reload。
此功能只在workerman以调试模式运行(启动时不加-d)才启用。windows用户需要执行windows.bat或者php windows.php才能启用。

关于输出语句

在传统php-fpm项目里,使用echovar_dump等函数输出数据会直接显示在页面里,而在webman开发过程中(调试模式启动时),这些输出往往显示在终端上,并不会显示在页面中(模版文件中的输出除外)。

不要执行exitdiesleep语句

执行die或者exit会使得进程退出并重启,导致当前请求无法被正确响应。业务执行执行die或者exit语句会导致进程退出,并显示WORKER EXIT UNEXPECTED错误。当然,进程退出了会立刻重启一个新的进程继续服务。如果需要返回,可以调用return

sleep语句会让进程睡眠,睡眠过程中不会执行任何业务,框架也会停止运行,会导致该进程的所有客户端请求都无法处理。

不要执行pcntl_fork函数

pcntl_fork用户创建一个进程,这在webman中是不允许的。

业务代码里不要有死循环

业务代码里不要有死循环,否则会导致控制权无法交还给workerman框架,导致无法接收处理其它客户端消息。

使用DE以及代码规范

项目团队应当尽量使用统一的IDE作为开发工具,并规范一致的代码规范配置项,如果使用的第三方代码规范及自动完成插件。如果团队成员较多而无法完全统一,最低限度,项目代码风格必须遵循PSR-1PSR-2规范。

助手函数

助手函数的初衷是为了简化代码和更方便记忆,但如果不是很清楚助手函数的内部实现原理,很容易导致滥用

由于现代的IDE提示和自动完成功能之强大,助手函数的作用非常有限,而且只会用助手函数对于框架的原理认识较浅,因此建议是掌握助手函数的内部实现原理后再来决定在项目规范中是否需要使用助手函数,以及如何使用。毕竟有些场景下,助手函数是非常简单实用的,例如:

public function get_user_info($id)
{
    $user = User::getOrEmpty($id);
    return json($user);
}

产品交付给客户的时候,有些时候助手函数能够让客户自定义模板的时候更方便。如果你需要额外定义或者覆盖原有的助手函数,可以直接在应用的functions.php公共文件中定义。

日志规范

日志记录建议直接使用PSR-3规范提供的接口方法记录,例如:

Log::log('info','开源技术小栈测试日志');
Log::log('error','开源技术小栈测试错误日志');

应当改为

Log::info('开源技术小栈测试日志');
Log::error('开源技术小栈测试错误日志');

支持的方法包括debuginfonoticewarningerrorcriticalalertemergency以及用于SQL日志记录的sql方法。

确保设置日志的最大数量限制$maxFiles,避免日志空间过大导致存储空间占满。

7 // $maxFiles

超过设置的数量后,最早的日志将会被自动清理。

路由规范

webman默认路由规则是http://127.0.0.1:8787/{控制器}/{动作}

默认控制器为app\controller\IndexController,默认动作为index

关闭路由

如果某个应用需要关闭路由功能,可以在应用的route.php配置文件中定义

Route::disableDefaultRoute();

明确定义请求类型

尽量明确定义路由的请求类型,提高路由解析的效率。

推荐使用:

Route::get('hello/{id}''index/hello');

替代:

Route::add(['GET'],'hello/{id}''index/hello');

路由路径必须以/开头

错误的用法

Route::any('test'function (Request $request) {
    return response('test');
});

正确的用法

Route::any('/test'function (Request $request) {
    return response('test');
});

多使用路由分组

可能的情况下,尽可能多使用路由分组。可以充分利用分组的匹配机制提高路由解析性能。

推荐使用

Route::group('/blog'function() {
    Route::get(':id$''blog/read');
    Route::get(':id/edit$''blog/edit');
});

不建议使用

Route::get('/blog/:id$''blog/read');
Route::get('/blog/:id/edit$''blog/edit');

路由变量定义规范

如果路由中存在参数,通过{key}来匹配,匹配结果将传递到对应的控制器方法参数中(从第二个参数开始依次传递),例如:

// 匹配 /user/123 /user/abc  Route::any('/user/{id}',  \[app\\controller\\UserController::class,  'get'\]);
namespace app\controller;
use support\Request;

class UserController
{
    public function get(Request $request, $id)
    
{
        return response('接收到参数'.$id);
    }
}

规范部署

请务必把你的WEB根目录指向public目录而不是应用根目录,并且不要随意更改入口文件的位置。public目录下面不要放除了入口文件和资源文件以外的其它应用文件。

保持环境一致性

在开发过程中,应该尽量保持你的测试环境和正式部署环境的一致性,包括运行环境和版本,无论在本地测试环境还是部署环境,都应当统一使用域名方式访问,本地可以使用测试域名,例如你的正式部署域名为webman.cn,那么本地测试环境可以使用webman或者webman.test作为测试域名,避免使用localhost或者127.0.0.1这种测试地址。对于有多个域名的部署应用,本地也要尽量模拟多个域名。

关闭调试模式

在部署到生产环境的时候,确保你已经关闭了调试模式,可以通过修改环境变量的方式关闭调试模式。

'debug' => true

无论是本地开发还是生产环境部署,都建议保持统一的配置文件,然后通过修改环境变量的方式(本地开发可以通过定义.env文件)设置区别部分。

关闭调试模式后,系统的健康状态和运行监控主要依靠日志或者你使用的监控服务。所以,要养成定时检查日志和运行状态的习惯。

部署忽略清单

项目根目录下面有一个.gitignore文件,用于定义提交版本库的时候哪些文件或者目录需要忽略,设置忽略的文件不会被同步到远程服务器,只是用于本地开发。

该文件默认内容如下,你可以根据项目的目录和规范进行调整。

/runtime
/.idea
/.vscode
/vendor
*.log
.env
/tests/tmp
/config/thinkorm.php

项目使用的核心框架以及composer安装的扩展,不应当被同步到版本库中,只需要同步composer.json以及composer.lock文件。然后在服务器端进行composer更新。

编写项目文档

每个项目都应该在根目录添加readme.md文件,并遵循Markdown规范写作,对项目做简要的说明(尤其是目录和代码规范),如果项目比较复杂,可以附上一个项目详细说明或者规范的文档地址,如果你的项目是前后端完全分离开发的话,应该事先规划好后台的API接口,然后创建一个API文档,便于指导前端开发人员进行接口调用,以及方便在线调试。

控制器规范

为了避免命名冲突,配置文件中统一开启控制器类库后缀。

'controller_suffix' => 'Controller',

支持在config/app.php设置控制器后缀,如果config/app.phpcontroller_suffix设置为空'',则控制器类似如下app\controller\Foo.php

<?php
namespace app\controller;

use support\Request;

class Foo
{
    public function index(Request $request)
    
{
        return response('hello index');
    }

    public function hello(Request $request)
    
{
        return response('hello webman');
    }
}

强烈建议将控制器后缀设置为Controller,这样能能避免控制器与模型类名冲突,同时增加安全性。

控制器建议继承一个公共的控制器类,便于统一调整和增加通用逻辑。默认安装后,你可以编写了一个BaseController实例基础控制器类,你可以根据自己项目的需求进行调整,包括改变命名空间。

对于控制器操作方法的拦截以及统一处理应当使用中间件独立操作,原来的初始化方法已经废弃。控制器中间件不需要继承任何的基础控制器类即可使用,仅仅需要你定义middleware属性即可。

控制器的代码应当尽量少,以确保逻辑清晰和可读性。并始终保持controller层作为访问控制器层的名称。

请求数据的验证操作统一使用验证器进行验证。操作方法中的对象使用依赖注入,其它的必要参数使用参数自动绑定。不要在操作方法中输出除了调试信息之外的任何内容,而是通过return返回需要输出的内容。

操作方法中始终明确响应输出的类型,默认的return方式使用的是HTML输出类型。

命名规范

数据表命名

数据表和字段采用小写加下划线方式命名,例如resty_user表和user_name字段,禁止使用驼峰、中文或者拼音作为数据表及字段命名。

字段规范

  • 主键统一使用id
  • 外键统一使用resource_id形式(例如user_id);
  • 模型数据字段统一使用小写+下划线命名,和数据表字段规范一致;
  • 数据表统一添加系统时间字段(create_timeupdate_time),并使用datetime类型;
  • 使用软删除并添加时间字段delete_time,类型和系统时间字段保持一致;
  • 模型类应该继承一个统一的公共类,便于调整和统一设置;
  • 如果是ThinkORM模型类应当通过定义autoWriteTimestamp属性明确时间字段类型;

查询规范

不要在数据库配置文件以外的地方配置或者动态设置数据库连接信息,包括模型内部。尽量不使用原生SQL查询,而应当使用查询构造器。

不要使用任何数据库工具创建、修改数据表和填充数据,应当使用数据迁移并同步版本库给所有成员。

每次数据查询都用Db类或者模型类的静态方法。避免在模型方法中直接写复杂的查询条件,而应当使用查询范围或者搜索器统一定义后调用。用查询表达式方式替代传统的数组查询。

查询数据的处理统一使用获取器定义,而不要直接处理数据。对写入数据需要额外处理的话统一使用修改器。

对于使用了SQL函数的用法,使用fieldRaworderRawwhereRaw/whereExp替代fieldorderwhere用法。

仅在使用字符串查询条件,以及调用whereExpwhereRaw方法的时候需要使用手动参数绑定,其余情况下都会自动进行参数绑定,禁止手动调用bind方法。

不要在WEB访问的时候进行大量数据操作,容易超时的数据处理应当在命令行下通过创建指令完成。

注:以下以使用ThinkORM关联模型说明

查询值为Null的数据

查询值为Null的数据应当使用whereNull或者whereNotNull方法

// 查询email为空,并且name不为空的用户数据
User::whereNull('email')
    ->whereNotNull('name')
    ->select();

使用快捷方法

对于一些常用的查询,尽量使用系统封装的快捷查询方法,例如:

User::whereIn('id', [1,2,3])
    ->whereLike('name''think%')
    ->select();

相当于下面的查询

User::where('id''in', [1,2,3])
    ->where('name''like''think%')
    ->select();

更多的方法可以参考官方手册或者使用IDE的自动提示。

获取字段值和列数据

对于一些简单的数据获取,你完全不需要查询整个表的数据,例如查询某个字段(满足条件的)值或者列数据。

// 获取id为10的用户名称
User::where('id'10)
    ->value('name');

// 获取状态为1的用户名称列表
User::where('status'1)
    ->column('name');

// 获取分数大于80的用户分数列表,以用户ID为索引
User::where('score''>'80)
    ->column('score''id');

聚合查询

如果你的min/max查询的是一个字符串类型字段,记得加上第二个参数并传入false

// 获取name字段的最大值
User::max('name'false);

时间区间查询

时间查询主要用于时间字段的区间查询,whereTime方法的优势是支持自动识别时间字段类型并进行转换处理。

// 大于某个时间
User::whereTime('birthday''>=''2008-10-1')
    ->select();
// 小于某个时间
User::whereTime('birthday''<''2000-10-1')
    ->select();
// 时间区间查询
User::whereBetweenTime('birthday''1990-10-1''2000-10-1')
    ->select();
// 不在某个时间区间
User::whereNotBetweenTime('birthday''1970-10-1''2000-10-1')
    ->select();

年/月/日/周查询

对于年/月/日/周的时间查询,推荐使用whereYear/whereMonth/whereDay/whereWeek方法查询,例如:

// 查询本月注册的用户
Db::name('user')
    ->whereMonth('create_time')
    ->select();   

// 查询上月注册用户
Db::name('user')
    ->whereMonth('create_time','last month')
    ->select();   

// 查询2018年6月注册的用户
Db::name('user')
    ->whereMonth('create_time''2018-06')
    ->select(); 

// 查询当天注册的用户
Db::name('user')
    ->whereDay('create_time')
    ->select();   

// 查询昨天注册的用户
Db::name('user')
    ->whereDay('create_time''yesterday')
    ->select();  

// 查询2018年6月1日注册的用户
Db::name('user')
    ->whereDay('create_time''2018-06-01')
    ->select();    

时间表达式查询

高级的时间表达式查询可以使用PHP的相对时间格式,例如:

// 查询两天以内的博客
Blog::whereTime('create_time','-2 days')
    ->select();

// 查询昨天中午后发的博客
Blog::whereTime('create_time','yesterday noon')
    ->select();

更多的时间表达式查询你可以自由发挥。

时间字段范围查询

你可以查询当前时间是否在两个时间字段区间范围内,通常用于一些活动以及优惠券的有效期查询等等。

// 查询有效期内的活动
Event::whereBetweenTimeField('start_time','end_time')
    ->select();

// 查询没有开始或者已经过期的活动
Event::whereNotBetweenTimeField('start_time','end_time')
    ->select();

字段比较

可以直接比较两个字段的大小进行查询

User::whereColumn('update_time''>''create_time')
    ->select();
User::whereColumn('score1''>''score2')
    ->select();

如果需要比较两个字段相同,可以使用

User::whereColumn('score1''score2')
    ->select();

条件查询

应当使用条件查询替代在组装查询条件的时候写大量的ifelse

User::when($condition, function ($query) {
    // 满足条件后执行
    $query->where('score''>'80)->limit(10);
})->select();

并且支持不满足条件的分支查询,并且支持多次调用when方法。

User::when($condition, function ($query) {
    // 满足条件后执行
    $query->where('score''>'80)->limit(10);
}, function ($query) {
    // 不满足条件执行
    $query->where('score''>'60);
})->select();

JSON查询

如果你的字段类型使用的是JSON类型,那么可以直接使用框架提供的JSON查询支持。

User::where('info->nickname''webman')
    ->find();

注意,需要在模型里面定义JSON字段属性。

<?php
namespace app\index\model;

use think\Model;

class User extends Model
{
 // 设置json类型字段
 protected $json = ['info'];
}

如果使用Db查询的话,可以改为

$user = Db::name('user')
 ->json(['info'])
    ->where('info->nickname','webman')
    ->find();

SQL函数查询

如果需要对某个字段使用SQL函数表达式查询,可以使用

User::whereExp('nickname'"= CONCAT(name, '-', id)")
    ->whereRaw('LEFT(nickname, 5) = ?', ['think'])
    ->select();

注意whereExpwhereRaw方法的区别,前者是对某个字段使用SQL函数表达式,后者是整个查询就是一个SQL函数表达式。

字段递增/递减

可以使用:

// 博客的阅读数递增1 评论数递减2
Blog::where('id'10)
    ->inc('read_count')
    ->dec('comment_count'2)
    ->save();

指定字段值排序

如果你需要按照指定字段的值的顺序来排序,可以使用

User::where('status'1)
    ->orderField('id', [1,2,3])
    ->select();

上传检测

网站的上传功能也是一个非常容易被攻击的入口,所以对上传功能的安全检查是尤其必要的。

系统的验证类提供了文件上传的安全支持,包括对文件后缀、文件类型、文件大小以及上传图片文件的合法性检查,确保你已经在上传操作中启用了这些合法性检查。

使用验证器

对于大量的表单需要验证的情况,建议使用验证器功能统一进行数据的合规验证。验证器的验证操作应该在控制器或者路由阶段使用validate方法进行处理,模型的数据验证功能新版已经取消不再建议使用,模型和数据库操作的时候应该传入经过安全处理过的数据。

XSS攻击

跨站脚本攻击(cross-site scripting,简称XSS),XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。

在渲染输出的页面中,要对一些数据进行安全处理,防止被恶意利用造成XSS攻击,如果是5.1版本的话,所有的输出都已经经过了htmlentities转义输出,确保安全。如果是5.0版本的话,你可以自定义一个xss过滤函数,在模板文件中对一些关键内容变量进行函数处理。

CSRF

CSRF 跨站请求伪造是 Web 应用中最常见的安全威胁之一,攻击者伪造目标用户的HTTP请求,然后此请求发送到有CSRF漏洞的网站,网站执行此请求后,引发跨站请求伪造攻击。攻击者利用隐蔽的HTTP连接,让目标用户在不注意的情况下单击这个链接,由于是用户自己点击的,而他又是合法用户拥有合法权限,所以目标用户能够在网站内执行特定的HTTP链接,从而达到攻击者的目的。

开启表单令牌验证,尽量开启强制路由并严格规范每个URL请求,定义单独的MISS路由规则。遵循请求类型的使用规范并做好权限验证,删除操作必须使用DELETE请求,数据更改操作必须使用POSTPUT或者PATCH请求方法,GET请求不应该更改任何数据。

以上就是高性能PHP框架 webman 开发规范1.0的详细内容,更多请关注全栈开发网其它相关文章!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 service@p2hp.com 进行投诉反馈,一经查实,立即处理!
-- -- 0

相关内容

如何使用 WinGet 在Windows上安装 PHP 8.4
如何使用 WinGet 在Windows上安装 PHP 8....
本文介绍了如何使用 winget 搜索、下载、安装、更新和删除 Windows PHP 二...
2025-02-20 11:28:50
现在你可以用一个命令安装 PHP 和 Laravel 安装程序
现在你可以用一个命令安装 PHP 和 Laravel 安装程...
创建第一个 Laravel 项目时,您需要确保先安装 PHP 和 Composer。但是,...
2024-10-17 15:32:51
如何在 PHP 中检测 n+1 查询
如何在 PHP 中检测 n+1 查询
n+1查询问题是软件开发中常见的性能问题。 N+1 查询会导致许多不必要的数据库调用。这可...
2024-05-11 12:58:01
为什么 Laravel 这么优秀
为什么 Laravel 这么优秀
Laravel 一直是我心中最优雅的后端框架,为了向更多的人解释为什么 Laravel 这...
2024-03-21 09:58:21
PHP老矣,尚能饭否?
PHP老矣,尚能饭否?
近日 GitHut 最新公布的数据显示,开发者在 GitHub 提交的 PR 中,所使用语...
2024-03-18 10:57:47
PHP老矣,尚能饭否? 近日 GitHut 最新公布的数据显示,开发者在 GitHub 提交的 PR 中,所使用语言为 PH...
为什么 Laravel 这么优秀 Laravel 一直是我心中最优雅的后端框架,为了向更多的人解释为什么 Laravel 这么优雅?框...
如何在 PHP 中检测 n+1 查询 n+1查询问题是软件开发中常见的性能问题。 N+1 查询会导致许多不必要的数据库调用。这可能会导致您...
现在你可以用一个命令安装 PHP 和 Laravel 安装程序 创建第一个 Laravel 项目时,您需要确保先安装 PHP 和 Composer。但是,如果您尚未...
我们都应该学习PHP PHP这三个字母官方的含义是这样的——PHP: Hypertext Preprocessor。但我想...
高性能PHP框架 webman 开发规范1.0 总结下webman最新版本的开发规范以及代码建议。欢迎大家提交自己更好的开发规范以及代码建议。
如何使用 WinGet 在Windows上安装 PHP 8.4 本文介绍了如何使用 winget 搜索、下载、安装、更新和删除 Windows PHP 二进制文件。...
PHP老矣,尚能饭否? 近日 GitHut 最新公布的数据显示,开发者在 GitHub 提交的 PR 中,所使用语言为 PH...
为什么 Laravel 这么优秀 Laravel 一直是我心中最优雅的后端框架,为了向更多的人解释为什么 Laravel 这么优雅?框...
如何在 PHP 中检测 n+1 查询 n+1查询问题是软件开发中常见的性能问题。 N+1 查询会导致许多不必要的数据库调用。这可能会导致您...

最新文章

如何使用 WinGet 在Windows上安装 PHP 8.4 本文介绍了如何使用 winget 搜索、下载、安装、更新和删除 Windows PHP 二进制文件。...
高性能PHP框架 webman 开发规范1.0 总结下webman最新版本的开发规范以及代码建议。欢迎大家提交自己更好的开发规范以及代码建议。
现在你可以用一个命令安装 PHP 和 Laravel 安装程序 创建第一个 Laravel 项目时,您需要确保先安装 PHP 和 Composer。但是,如果您尚未...
如何在 PHP 中检测 n+1 查询 n+1查询问题是软件开发中常见的性能问题。 N+1 查询会导致许多不必要的数据库调用。这可能会导致您...
为什么 Laravel 这么优秀 Laravel 一直是我心中最优雅的后端框架,为了向更多的人解释为什么 Laravel 这么优雅?框...
PHP老矣,尚能饭否? 近日 GitHut 最新公布的数据显示,开发者在 GitHub 提交的 PR 中,所使用语言为 PH...
我们都应该学习PHP PHP这三个字母官方的含义是这样的——PHP: Hypertext Preprocessor。但我想...