StartMVC开发手册

可以快速上手的开发文档

手册目录

助手函数(内置)

功能概述

StartMVC 内置了一批全局助手函数,用于简化配置读取、输入取值、缓存操作、数据库查询、输出转义与数据验证等高频操作。它们主要定义于 startmvc/function.php(CSRF 相关助手位于 function/csrf.php,见「Csrf防护类」一章),在框架启动时自动加载,无需引入即可直接调用。

一览
函数用途
env()读取环境变量
lang()读取多语言包
input()取输入值(取值 + 类型转换 + 默认兜底)
e()HTML 转义输出
dump()格式化输出变量
config()读取 / 设置配置
cache()缓存存取与删除
url()生成 URL 地址
db()数据库链式操作
model()实例化模型 新增
get_ip()获取客户端真实 IP
request()获取当前请求对象 新增
session()Session 存取(读 / 写 / 删 / 全部) 新增
cookie()Cookie 存取(读 / 写 / 删 / 全部) 新增
redirect()跳转(立即中断并重定向) 新增
json()JSON 响应(立即中断并输出) 新增
logger()日志记录(PSR-3 八级,占位符插值) 新增
abort()中断请求并抛出 HTTP 状态异常(401 / 403 / 404...) 新增
validate()数据验证(规则在前,自动取请求输入,收集全部字段错误) 新增
csrf_token() / csrf_field() / csrf_meta()CSRF 令牌(见「Csrf防护类」)

env(key, default = null)

读取环境变量,并自动转换常见字面量。环境变量来源于项目根目录的 .env 文件或系统环境变量。

  • 参数:$key 变量名,$default 不存在时的默认值
  • 转换规则:true / (true) → true;false / (false) → false;null / (null) → null
  • 使用:
// .env 中:APP_DEBUG=true
$debug = env('APP_DEBUG'); // true(布尔值,非字符串)
$host = env('DB_HOST', '127.0.0.1'); // 不存在时返回默认值

lang(key, default = '', module = null)

获取语言包中的翻译文本,语言包位于 app/{模块}/language/{语言}.php。

  • 参数:$key 语言键名,$default 默认值,$module 指定模块(缺省取当前路由上下文的模块)
  • 回退规则:语言包或键不存在时,依次回退「默认值 → 键名本身」,不抛异常
  • 使用:
lang('welcome'); // 取当前模块语言包
lang('welcome', '欢迎'); // 未命中时返回默认值
lang('welcome', '欢迎', 'admin'); // 指定 admin 模块的语言包

input(key = null, default = null, type = '', filter = false)

取输入值,合并 GET 与 POST(POST 优先),一步完成「取值 + 类型转换 + 默认兜底」。键名支持点路径读取嵌套数组。

  • 参数:
    • $key 键名,支持点路径(如 user.name / list.0.id);留空返回全部输入
    • $default 取值失败时的默认值
    • $type 类型转换:'' / string / int / float / bool / array
    • $filter 是否 HTML 转义,默认 false
  • 使用:
input('id'); // 取 id(字符串)
input('id', 0, 'int'); // 转 int,缺省 0
input('user.name'); // 点路径:$_POST['user']['name']
input('list.0.id', 0, 'int'); // 点路径下钻 + 类型转换
input('agree', false, 'bool'); // 宽松布尔:'false'/'0'/'off' 均判为 false
input('title', '', 'string', true); // 取值并转义
input(); // 返回全部输入(GET + POST 合并)
点路径取值:路径中任一层不存在时安全回退默认值,不会触发未定义索引告警。
与 Request 的关系:input() 是 Request::input() 的语法糖,内部读取容器中绑定的当前请求实例,因此中间件附加的数据同样可读。
数据来源:需单独读取 GET 或 POST 时,请使用 Request::get() / Request::post()。

e(value, doubleEncode = true)

HTML 转义输出助手,用于输出侧防止 XSS。与输入端「不转义」策略配套:输入层保持原始数据,输出到 HTML 时统一在此转义,避免双重转义与数据污染。

  • 参数:$value 待转义的值(传入数组将递归转义),$doubleEncode 是否对已是 HTML 实体的内容再次转义,默认 true
  • 使用:
// 模板中输出用户输入,防止 XSS
echo e($userInput); // <script> → &lt;script&gt;

// 列表递归转义,便于直接渲染
foreach (e($list) as $item) { ... }

// 值已是 HTML 实体时,避免二次转义
echo e('&amp;', false); // &(而非 &amp;amp;)

// null 返回空字符串,避免输出告警
echo e(null); // ''
转义原则:输入不转义、输出必转义。请勿在输入端开启 filter 又在输出端调用 e(),否则会出现 &amp;amp; 之类的双重转义。

dump(var, label = null, echo = true)

格式化输出变量内容,自动适配 CLI 与 Web 环境。

  • 参数:$var 要输出的变量,$label 标签,$echo 是否直接输出(为 false 时仅返回字符串)
  • 使用:
dump($data, '调试信息');

// 仅返回字符串,不直接输出
$str = dump($data, '调试信息', false);

config(key = null, default = null)

读取或设置配置项。配置项支持以 . 分隔的层级键名。

  • 参数:$key 配置键名(传数组则为批量设置),$default 读取时的默认值
  • 使用:
config(); // 获取全部配置
config('debug'); // 读取单个配置
config('db.host'); // 读取层级配置
config('db.host', 'localhost'); // 读取,不存在时返回默认值
config(['debug' => true]); // 批量设置配置

// 加载指定配置文件(键名前加 @)
config('@route');
注意:config($key, $value) 的第二参数是读取时的默认值,而非「设置值」。需要写入配置请传入数组,或使用 Config::set()。

cache(name, value = null, ttl = null, driver = null)

缓存数据的存取与删除。

  • 参数:$name 缓存名称,$value 缓存值(null 表示获取、false 表示删除),$ttl 过期秒数(null 时使用驱动配置的默认值),$driver 驱动类型
  • 使用:
cache('user_1'); // 获取缓存,未命中返回 null
cache('user_1', $userData); // 写入缓存(使用驱动默认过期时间)
cache('user_1', $userData, 7200); // 写入缓存,2 小时后过期
cache('user_1', false); // 删除缓存
cache('user_1', $userData, 7200, 'redis'); // 指定驱动
$ttl 缺省为 null,此时由缓存驱动使用 config/cache.php 中配置的默认过期时间,而非固定 3600 秒。

url(url)

生成 URL 地址,自动处理 URL 重写与后缀。

  • 参数:$url 路径
  • 使用:
url('home/index'); // 开启重写:/home/index.html
 // 未开启: /index.php/home/index.html

db(table = '', config = [])

数据库操作助手,支持链式调用与自定义配置。

  • 参数:$table 表名,$config 数据库配置(可选)
  • 使用:
// 使用默认配置
db('user')->where('id', 1)->get();

// 链式指定表名
db()->table('user')->where('status', 1)->select('id,name')->get();

// 使用自定义配置
db('user', $config)->where('uid', 1)->get();

// 写入与更新
db('user')->insert(['name' => 'test', 'email' => 'test@example.com']);
db('user')->where('id', 1)->update(['name' => 'updated']);
db('user')->where('id', 1)->delete();

model(name, module = null)

模型助手,按 app\{模块}\model\{名称}Model 规则解析并实例化模型类,与控制器的 $this->model() 同源。此前模型入口是控制器的 protected 方法,模板、事件监听器、中间件与 CLI 里拿不到模型实例,model() 补上这个入口。模板、事件监听器等场景中同样可直接调用。

  • 参数:$name 模型名(不带 Model 后缀,如 'user' 对应 UserModel 类),$module 模块名(缺省取当前路由上下文的模块,CLI 下回退 default_module 配置)
  • 使用:
// 当前模块(home)的 UserModel:app\home\model\UserModel
$userModel = model('user');

// 指定 admin 模块的 LogModel:app\admin\model\LogModel
$logModel = model('log', 'admin');

// 直接链式查询
$user = model('user')->where('id', 1)->find();
$total = model('user')->count();

模板内同样可用(模板表达式标签 {echo}):

{echo model('user')->count()}
每次调用都返回新实例(未做单例绑定时不缓存),避免 where 条件等查询状态在多次调用间串味。模型类不存在时由容器抛出异常。

get_ip()

获取客户端真实 IP 地址,支持代理环境。

  • 参数:无
  • 使用:
$ip = get_ip();
仅在 REMOTE_ADDR 命中可信代理列表(config: trusted_proxies)时才解析 X-Forwarded-For,否则一律返回 REMOTE_ADDR,防止通过伪造请求头绕过登录日志、限流与审计。

request()

请求助手,返回贯穿本次请求的 Request 实例。它取自容器中绑定的唯一快照,与控制器 $this->request、中间件拿到的是同一份数据,中间件附加的状态不会丢。

  • 参数:无。取输入值请用 input(),两者分工:request() 给请求对象本身(可链式调用全部 Request API),input('key') 是取值的极简语法糖
  • 回退规则:请求实例尚未绑定容器时(纯 CLI、早期引导阶段),回退为基于当前超全局变量构造的临时实例,调用不会报错
  • 使用:
if (request()->isPost()) { ... } // 请求类型判断
$id = request()->get('id', ['type' => 'int']); // 取 GET 参数并转 int
$ua = request()->header('User-Agent'); // 读请求头
$method = request()->method(); // 请求方法
与静态调用 Request::get() 的区别:静态形式经 __callStatic 每次新建临时实例,会丢掉中间件附加的数据;request() 始终指向容器绑定的同一实例。在模板、事件监听器、路由闭包中需要完整请求上下文时,一律用 request()。

session(key = null, value = null, default = null)

Session 存取助手,与 cache() 同一套三元约定:第二个参数 null 表示读取、false 表示删除、其余值写入。与 Session 静态调用同源,自动处理会话键前缀(config/common.php 的 session_prefix)。

  • 参数:$key 键名(留空返回全部会话数据),$value 写入值(null 读取 / false 删除),$default 读取时的默认值
  • 使用:
session('user'); // 读(未命中返回 null)
session('user', null, []); // 读,未命中返回 []
session('user', ['id' => 1]); // 写,返回写入值
session('user', false); // 删
session(); // 全部会话数据(自动去前缀)
三元约定与 cache() 完全一致,学一个等于会两个。需要存字面 null 值时请直接调用 Session::set()。注意:session_prefix 配置为空串时(默认),session() 无参调用返回空数组——前缀用于区分框架会话键与 PHP 自身的会话键(如 PHPSESSID),建议配置非空前缀。

cookie()

Cookie 存取助手,与 session() 同一套三元约定:第二参为 null 表示读取、false 表示删除、其余值为写入;键名自动处理 cookie_prefix 前缀。

cookie('token'); // 取(未命中返回空串 '')
cookie('page', null, ['default' => 1, 'type' => 'int']); // 取,带默认值与类型转换
cookie('token', 'abc', ['expire' => time() + 3600]); // 写(1 小时后过期)
cookie('token', false); // 删
cookie(); // 全部 Cookie(自动去前缀)
  • 参数:cookie($key = null, $value = null, array $options = [])。第三参是 $options(区别于 session() 的 $default)——Cookie 写入离不开 expire 这类选项,与 ThinkPHP 的 cookie($name, $value, $option) 同形
  • 读取选项:default(未命中默认值,缺省空串)、type(int / string / float / bool / array)、filter(true 时 HTML 转义)、function(处理函数名,如 'trim')
  • 写入 / 删除选项:expire(过期时间戳,默认 0 会话级)、path、domain、secure(支持 'auto' 自动检测 HTTPS)、httponly(默认 true)、samesite(默认 Lax)
  • 安全默认值:写入时自动带 HttpOnly、SameSite=Lax,secure 按配置或 HTTPS 自动检测——详见「Cookie」一章
  • 与 session() 的两处差异:① 未命中返回 $options['default'](缺省空串 '',不是 null),需区分未命中与空串时用 Cookie::has();② 写入 / 删除返回 bool(读取仍返回值)
需要存字面 null 值时请直接调用 Cookie::set()(与 cache() / session() 约定一致)。Cookie 的写入只影响浏览器下一次请求带回的值,当前请求内读不到刚写入的值。

redirect()

跳转助手,构建 Location 响应并立即中断执行(抛出 HttpResponseException,由 App::run 统一捕获发送)——与 Controller::redirect() 的「调用即终止」语义一致,因此中间件、模板、事件监听、模型等控制器之外的位置也能跳转。

redirect(url('user/login')); // 302 临时跳转(站内地址配合 url() 生成,自动带 url_suffix / 重写规则)
redirect('https://example.com', 301); // 301 永久跳转(外链直接传完整 URL)
  • 参数:redirect($url, $status = 302)。状态码支持 301 永久 / 302 临时(默认)/ 303 / 307 / 308;$url 为空时回退跳转首页 '/'
  • 与 Controller::redirect() 同源:控制器版本已委托本助手并补齐 $status 参数(此前固定 302),控制器内外行为完全一致
  • 调用即终止:后续代码不再执行,等价于在当前位置抛出响应异常;不要试图「跳转后继续执行」
  • 站内地址建议套 url():redirect(url('user/login')) 自动携带伪静态后缀与重写规则;外链直接传完整 URL,会原样输出(含查询串)
  • 调试面板:重定向响应不附加 trace 面板(Response::shouldTrace 已排除无响应体的 3xx)
在模板中需要「输出一个跳转链接」而不是「立即跳转」时,请使用 url() 或 <a> 标签——redirect() 一旦调用当前请求就结束了。

json()

JSON 响应助手,构建 application/json; charset=utf-8 响应并立即中断执行(抛出 HttpResponseException,由 App::run 统一捕获发送)——与 redirect() / Controller::json() 的「调用即终止」语义一致,中间件、路由闭包、事件监听、模型等控制器之外的位置也能直接输出 JSON。

json(['code' => 0, 'msg' => 'ok']); // 200 正常返回
json(['error' => '未登录'], 401); // 指定 401 状态码
  • 参数:json($data, $status = 200)。数据支持数组 / 对象 / 标量;$status 为 HTTP 状态码,比 Controller::json() 多出此参数(控制器版本只有默认 200)
  • 中文不转义:编码带 JSON_UNESCAPED_UNICODE,中文原样输出(如 "name":"张三" 而非 \u5f20\u4e09)
  • 调用即终止:后续代码不再执行;适合在中间件里做鉴权失败返回 JSON 错误、在路由闭包里一行输出 API 结果
  • 与 Response::json() 的分工:需要构建 JSON 响应但不立即发送(继续链式设置响应头 / Cookie)时,直接调用 (new Response())->json($data)——它返回 Response 实例,不抛异常
响应类助手成对使用:redirect() 管跳转、json() 管 JSON 输出,都是「调用即终止」——一旦调用当前请求就结束了。需要「继续执行再输出」的场景请构建 Response 后随控制器返回值交给统一出口发送。

logger()

日志记录助手(PSR-3 风格),委托框架 Logger 类写入,控制器、模型、中间件、模板等任意位置一行记录。首次调用实例化并缓存共享 Logger 实例(Logger 无请求状态,共享安全),后续调用直接复用,不再重复读配置与准备目录。

logger('info', '用户登录', ['uid' => 1]);
logger('error', '支付回调失败: {reason}', ['reason' => '超时']); // {占位符} 自动插值
  • 参数:logger($level, $message, array $context = []),与 CodeIgniter 的 log_message() 同签名。$level 为 PSR-3 八级:debug / info / notice / warning / error / critical / alert / emergency;$message 支持 {占位符} 配合 $context 插值(值须为字符串或数字)
  • 返回 bool:是否真正写入。总开关关闭(config/log.php 的 enabled => false)、低于最低记录级别(level 配置,默认 debug)、目录不可用或写入失败均返回 false——Logger 写入永不抛异常(异常处理器自身也要依赖它记日志,日志失败不能反过来打断业务)
  • 级别 fail-fast:传入八级之外的级别抛 InvalidArgumentException——级别写错属于调用方 bug,当场暴露;写入失败属于环境故障,静默返回,两者分开处理
  • 日志文件:runtime/logs/{日期}_{级别}.log,按天按级分文件、天然按天轮转;split => false 时合并为 {日期}.log。行格式 [Y-m-d H:i:s] LEVEL: 消息
  • 目录退化:配置目录(path,留空用 runtime/logs)不可写时自动退化为系统临时目录,仍不可用则静默丢弃返回 false
Logger 实例另有 ->debug() / ->error() 等 8 个快捷方法(与 log() 同参),logger() 统一走 ->log($level, ...) 单入口,在容器尚未就绪的场景也可直接使用。生产环境建议把 config/log.php 的 level 调到 warning,避免 debug 日志堆积。

abort($code, $message = '', array $headers = [])

HTTP 异常助手,抛出携带状态码的 HttpException 并立即中断执行,由框架统一渲染对应错误响应:非 Ajax 请求按状态码出错误页(404 复用站点 404 页,其余状态码展示「状态码 + 消息」),Ajax 请求输出同状态码的 JSON。与 redirect() / json() 同属「调用即终止」家族,区别在于中断原因是 HTTP 层错误(401 / 403 / 404 / 429...)——普通 throw new \Exception 一律落 500,需要自定义状态码时用本函数。

abort(404); // 页面不存在(默认消息 Not Found)
abort(403, '无权访问'); // 权限拒绝,错误页展示此消息
abort(429, '请求过于频繁', ['Retry-After' => '60']); // 附带响应头

// 中间件鉴权:一行完成「判断 + 中断」
if (!$request->header('X-Token')) {
 abort(401, '未登录');
}
  • 参数:$code HTTP 状态码(限 400~599,越界抛 InvalidArgumentException——abort 的语义是「中断并报错」,2xx / 3xx 应走正常返回或 redirect());$message 错误消息,面向客户端展示,留空时使用状态码默认短语(如 403 缺省 Forbidden);$headers 附加响应头(键名 => 值)
  • 渲染规则:非 Ajax——404 复用 core/tpl/404.php 专属页(静态文案),其余状态码用 core/tpl/http_error.php 展示状态码 + 消息;Ajax——输出 {error: 消息, code: 状态码} 的 JSON,状态码同 $code。错误页均不附加 trace 面板
  • 消息不受 debug 开关隐藏:abort() 的消息是开发者写给客户端看的(如「无权访问」),错误页恒展示;普通异常页在非 debug 下只显示通用文案,两者定位不同
  • 日志策略:4xx 属预期内的客户端错误(权限 / 不存在 / 参数错),不写错误日志,避免刷爆日志;5xx 仍是服务端问题,照常记录
  • 可捕获:抛出的是 startmvc\core\HttpException,需要接管时 try / catch (HttpException $e) 即可,getStatusCode() / getMessage() 分别取状态码与消息
与 Controller::error() 的分工:$this->error('删除失败') 是业务反馈(Ajax 回 code=0 的 JSON / 普通请求出跳转提示页),abort(403, '无权访问') 是 HTTP 层中断——前者告诉用户「操作没成功」,后者告诉客户端「这次请求在 HTTP 语义上不通过」。

validate(array $rules, ?array $data = null)

验证助手,一行完成「new Validator + setRules + validate + getError」四步。规则语法与「数据验证类」一章、Model 的 $validate 属性完全同套,可无缝迁移。

// 最常用:规则在前,自动验证当前请求全部输入(POST 优先,GET 兜底)
$ok = validate(['mobile' => 'isMobile', 'code' => 'required|minlen:4|maxlen:6']);

// 验证指定数据(非请求来源,如数据库记录)
$ok = validate(['age' => 'isNatural'], ['age' => $row['age']]);

// 失败返回「字段 => 错误信息」数组,配合 json() 一行出校验失败响应
if ($ok !== true) {
 json(['error' => $ok], 422);
}
  • 参数:$rules 验证规则(键为字段名,值为规则串或嵌套数组);$data 待验证数据,省略(null)时自动取 input() 全量请求输入
  • 返回值:通过返回 true;失败返回 ['字段' => '错误信息', ...](恒非空数组)。判断务必用 $ok !== true 严格比较,不要依赖宽松比较
  • 收集全部错误:内部固定 setFailFast(false),多字段失败时一次收齐(每字段一条),便于表单一次点亮全部红框、JSON 一次返回;需要「首个错误即中止」的快速失败语义,请直接使用 Validator 类
  • 规则语法:'规则1|规则2:参数' 管道多规则,: 后参数按逗号拆;'`昵称`required' 单反引号里是字段别名(错误消息用别名展示);'required``昵称不能为空``' 双反引号里是自定义错误消息;'user' => ['name' => 'required'] 嵌套数组规则
  • 可选字段:非 required 字段缺失或为空时跳过其余规则(不强制校验);未知规则判为失败并给出调用错误提示,不会静默通过
与 Model 自动验证的分工:模型的 $validate 属性走写入前自动验证;validate() 用于控制器 / 中间件 / 闭包里手动验证任意数据。需要更多控制(如 setTagMap 自定义规则、getData() 取过滤后数据)时,直接实例化 startmvc\core\Validator,详见「数据验证类」一章。