declare(strict_types=1) 必须置于文件首行(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 构造器等需要明确契约的地方。
立即学习
“
PHP免费学习笔记(深入)
”;
支持标量类型:
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 的子类,但单独命名便于捕获)。
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
容易踩的坑:
传入
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)
存在且位置正确,并理解“检查发生在调用侧”这个关键机制。否则很容易以为加了类型就万事大吉,结果上线后才发现参数悄悄被转成了意外值。