env() 读取 .env 中所有值均为字符串,需显式类型转换;如 (int)env('DB_PORT'),并清除配置缓存以生效,双引号写法存在变量展开风险,推荐不加引号或单引号。

env() 读取数字返回字符串而非 int/float
ThinkPHP 的 env() 函数底层依赖 vlucas/phpdotenv,它**一律将 .env 中所有值解析为字符串**,哪怕写的是 DB_PORT=3306 或 APP_DEBUG=true。这不是 ThinkPHP 的 bug,而是 dotenv 的设计约定——它不尝试类型推断,避免歧义和隐式转换风险。
常见错误现象:'hostport' => env('DB_PORT', 3306) 看似写了默认值 3306(整数),但实际从 .env 读到的 env('DB_PORT') 是字符串 "3306";若后续代码用它做数值比较或传给需要 int 的扩展(如 PDO 构造参数),可能静默失败或触发警告。
- 必须显式类型转换:在配置文件中对已知应为数字的字段手动 cast,例如
'hostport' => (int) env('DB_PORT', 3306)或'timeout' => (float) env('DB_TIMEOUT', 10.0) - 布尔值更危险:
APP_DEBUG=true读出来是字符串"true",不是 PHPtrue;要用filter_var(env('APP_DEBUG'), FILTER_VALIDATE_BOOLEAN)或自定义判断逻辑 - 不要依赖
==松散比较:比如env('DB_PORT') == 3306可能为 true,但env('DB_PORT') === 3306一定为 false,生产环境建议一律用严格比较 + 显式转换
.env 里写数字要不要加引号
不加引号是安全的,但加了单引号也 OK;双引号则可能出问题。
DB_PORT=3306 ✅ 和 DB_PORT='3306' ✅ 都会被解析为字符串 "3306";而 DB_PORT="3306" ❌ 在部分 shell 环境下可能被提前展开(尤其当值含 $ 或 ` 时),且不符合 dotenv 推荐格式。
立即学习“PHP免费学习笔记(深入)”;
- 纯数字、无特殊字符:直接写
KEY=123,最简洁可靠 - 含空格或符号(如
API_TIMEOUT=30.5):用单引号包裹API_TIMEOUT='30.5',避免解析歧义 - 绝对不要用双引号包裹数字:既无必要,又埋下潜在变量展开隐患
为什么 config/database.php 里用 (int) 转换后还是报错
最常见原因是缓存没清——ThinkPHP 把整个 config/database.php 执行结果缓存成 PHP 文件,类型转换逻辑只在首次加载时执行一次。改了 (int) env(...) 却没清缓存,框架仍运行旧缓存代码。
- 每次修改配置文件中的类型转换逻辑后,必须执行:
php think clear:config和php think optimize:config - 验证是否生效:在控制器中打印
var_dump(gettype(env('DB_PORT')));和var_dump(gettype((int) env('DB_PORT')));,确认转换发生 - 注意
env()默认值类型也要匹配:如果写env('DB_PORT', '3306'),默认值是字符串,(int) '3306'没问题;但如果误写成env('DB_PORT', 3306),默认值是 int,而.env读出来是 string,两者行为一致,但语义混乱,建议默认值也统一用字符串再转
Env::get() 和 env() 选哪个
在 ThinkPHP 6+ 中,env() 是全局函数,本质就是对 Env::get() 的封装;二者行为完全一致。但有细微差别:
-
env('KEY', 'default')更短,适合配置文件中高频使用 -
Env::get('KEY', 'default')显式表明来源,便于 IDE 跳转和静态分析,适合复杂逻辑中强调“这是环境变量” - 两者都返回字符串,类型转换责任仍在你手上——没有哪个会自动帮你转 int
- 别混用:同一项目中固定用一种,避免维护困惑
真正容易被忽略的是:类型转换必须落在配置数组生成过程中,而不是等 Db 类运行时再去 cast;否则数据库连接器拿到的仍是原始字符串,PDO 可能拒绝或静默截断。



















