declare(strict_types=1) 必须置于文件首行(

PHP 7+ 的 declare(strict_types=1) 怎么开、开在哪
严格类型模式不是全局开关,它只对声明了它的单个文件生效,且必须是文件第一行(除 PHP 开头标签外)。放错位置会直接报语法错误或完全不生效。
常见错误现象:declare(strict_types=1) 写在 namespace 后、注释后、甚至函数体内——这些都会被忽略,类型检查退化为弱类型行为。
- 必须写在
之后、任何其他语句之前 - 不能跨文件继承:A.php 开了 strict,require B.php 不会让 B.php 自动变 strict
- 仅影响当前文件的函数调用(含内置函数和用户函数),不影响变量赋值或运算符比较
参数类型声明和返回类型声明怎么写才真正生效
类型声明本身不依赖 strict 模式,但是否强制校验取决于 strict 模式。比如 function foo(int $x): string,在非 strict 下,foo("123") 会被静默转成 int;strict 下则直接抛 TypeError。
使用场景:适合 API 入口、核心业务逻辑、DTO 构造器等需要明确契约的地方。
- 支持标量类型:
int、string、bool、float(PHP 7.0+) - 支持
void、mixed(PHP 8.0+)、never(PHP 8.1+)等返回类型 - 数组类型需用
array或list/non-empty-array(PHP 8.1+),不能写[] - 可空类型统一用
?Type语法,如?string,不是string|null(后者仅在联合类型中合法)
TypeError 和 ArgumentCountError 哪些情况会触发
strict 模式下,类型不匹配不再静默转换,而是抛出 TypeError;而参数数量不对则抛 ArgumentCountError(也是 TypeError 的子类,但单独命名便于捕获)。
容易踩的坑:
- 传入
null给非可空参数:即使开了 strict,function bar(string $s)调用bar(null)仍报TypeError - 传入对象给标量类型提示:如
function baz(int $n)+baz(new DateTime())→ 强制失败,不会调__toString()或__invoke() - 联合类型中类型顺序无关,但
int|float和float|int等价;不过string|int传"123"在 strict 下仍失败(字符串不自动转 int)
为什么有些类型声明看起来“没起作用”
最常见原因是:你开了 strict,但调用的是另一个没开 strict 的文件里的函数——类型检查只发生在调用点,而不是定义点。也就是说,foo(3.14) 是否报错,取决于 foo 的定义文件是否启用了 declare(strict_types=1),而不是调用它的文件。
另一个盲区:数组键类型、对象属性类型、foreach 中的解构变量,PHP 均不提供运行时类型检查,它们不属于函数签名范畴。
- 类属性类型(PHP 7.4+)如
public int $id;是运行时检查,与 strict 模式无关 - 数组解包
[$a, $b] = $arr不受类型声明约束,哪怕$a已声明为int - 闭包的类型声明同样遵循 strict 文件规则,但匿名函数内嵌定义时容易误判作用域
真正要让类型检查落地,得逐个文件确认 declare(strict_types=1) 存在且位置正确,并理解“检查发生在调用侧”这个关键机制。否则很容易以为加了类型就万事大吉,结果上线后才发现参数悄悄被转成了意外值。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











