功能概述
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> → <script>
// 列表递归转义,便于直接渲染
foreach (e($list) as $item) { ... }
// 值已是 HTML 实体时,避免二次转义
echo e('&', false); // &(而非 &amp;)
// null 返回空字符串,避免输出告警
echo e(null); // ''
filter 又在输出端调用 e(),否则会出现 &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()}
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
->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, '未登录');
}
- 参数:
$codeHTTP 状态码(限 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字段缺失或为空时跳过其余规则(不强制校验);未知规则判为失败并给出调用错误提示,不会静默通过
$validate 属性走写入前自动验证;validate() 用于控制器 / 中间件 / 闭包里手动验证任意数据。需要更多控制(如 setTagMap 自定义规则、getData() 取过滤后数据)时,直接实例化 startmvc\core\Validator,详见「数据验证类」一章。