strict_types=1仅对声明所在文件生效,类方法类型检查是否触发取决于调用方文件是否启用该声明;若调用文件未声明,则即使类文件已声明,传入错误类型也不会抛typeerror。

类中不加 declare(strict_types=1);,类型声明就形同虚设——它只对当前文件生效,而类方法的调用行为完全取决于调用方所在文件是否启用严格模式。
为什么类方法的类型检查会“失效”?
PHP 的 strict_types 不是全局开关,也不是类定义时绑定的属性。它只在「函数被调用的那一刻」起作用,且只看调用语句所在的文件有没有声明 declare(strict_types=1);。
常见错误现象:
- 你在
User.php里写了declare(strict_types=1);并定义了function setName(string $name): void,但调用它的index.php没声明 strict_types → 传入123或null仍能静默通过 - IDE 显示类型提示正常,静态分析工具(如 PHPStan)也报错,但运行时却没抛
TypeError→ 因为调用点没启用严格模式
类文件必须独立声明 declare(strict_types=1);
类本身不是执行单元,但类中的方法会被不同上下文调用。要确保方法体内的参数校验真正生效,声明必须落在类文件顶部(<?php 后第一行),且不能被注释、空行或 BOM 打断。
正确写法:
<?php declare(strict_types=1);
class User
{
public function setId(int $id): void
{
// ...
}
}
容易踩的坑:
-
declare写在命名空间或 use 语句之后 → 解析失败,整个声明被忽略 - 类文件通过
require被引入,但主入口没声明 → 该类方法仍按弱类型运行 - 使用 trait 时,trait 文件没声明 strict_types,即使宿主类声明了,trait 中的方法调用也不受保护
对象类型声明在严格模式下才真正“防错”
PHP 7.2+ 支持 object 类型提示,但即使写了 function process(object $input),若调用方未启用 strict_types,传入 ['foo' => 'bar'] 这样的数组也不会报错——PHP 会尝试调用 __toString() 或直接让 zval 类型检查绕过。
只有在调用点启用严格模式后,以下行为才会触发 TypeError:
- 传入
null给非可空object参数 - 传入标量(
string、int)给object参数 - 传入子类实例给父类类型声明时,若父类声明为 final 或接口不匹配,也会在校验阶段暴露
性能与兼容性:不是代价,而是必要开销
启用 declare(strict_types=1); 几乎不带来运行时性能损耗——类型检查发生在 Zend VM 的参数绑定阶段,属于轻量级 zval 类型标志(IS_OBJECT、IS_LONG 等)比对。
但要注意:
- PHP 7.0+ 才支持标量 strict_types,低于此版本会直接 Parse Error
- 第三方库若未启用 strict_types,你无法强制它遵守;只能在自己的调用层做包装或断言
- 严格模式不改变返回值类型提示的行为——
: object在 strict_types=1 下仍要求返回真实对象,否则抛错
最常被忽略的一点:类方法的类型安全,从来不是靠「定义时写了什么」,而是靠「谁在哪儿调用了它」。不统一每个参与文件的 declare,等于在关键路径上留了一扇没锁的门。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











