strict_types=1 必须放在文件最开头,它是一条编译指令,因此 declare(strict_types=1) 必须是 PHP 文件中除空白符和注释外的第一条语句。

strict_types=1 必须放在文件最开头
它不是函数调用,也不是配置项,而是一条编译指令 —— 所以 declare(strict_types=1) 必须是 PHP 文件中除 <?php 开标签外的第一条语句。任何空格、BOM、注释、echo、include 都会导致 Parse error。
常见错误现象:
-
Parse error: syntax error, unexpected 'declare' (T_DECLARE)—— 因为前面有空白或注释 - 文件开头用了 UTF-8 BOM,肉眼不可见但会破坏位置要求
- 写在命名空间声明之后:
namespace App; declare(strict_types=1);→ 直接报错
正确写法只有一种:
<?php
declare(strict_types=1);
namespace App;
function add(int $a, int $b): int { return $a + $b; }
strict_types 只影响当前文件的函数调用
它不跨文件生效。即使你在 foo.php 里写了 declare(strict_types=1),然后 include 'bar.php',bar.php 里的函数调用仍按自己的 declare 设置执行(或默认弱类型)。
立即学习“PHP免费学习笔记(深入)”;
这意味着:
- 不能靠“父文件开启 strict”来约束被包含文件的参数校验
- 每个需要严格校验的文件都得单独加
declare(strict_types=1) - Composer 自动加载的类文件,也必须各自声明才生效
典型陷阱:你在一个入口文件开了 strict,以为整个请求链都受控,结果实际出错的函数在另一个没声明的类文件里 —— 它依然做隐式转换,掩盖了问题。
ticks 和 encoding 已基本淘汰,别乱用
declare(ticks=1) 和 declare(encoding='...') 是 PHP 5 时代的遗留特性,现在极少有合理使用场景:
-
ticks依赖register_tick_function(),性能开销大、行为难预测,现代替代方案是事件循环或信号处理(如 pcntl),而不是靠解释器周期性回调 -
encoding在 PHP 5.3+ 默认被忽略,除非编译时加了--enable-zend-multibyte(绝大多数发行版没开),且和命名空间混用会直接解析失败 - PHP 7.2+ 已移除
encoding的运行时效果,文档明确标记为“deprecated”
除非你维护十年前的老系统,否则看到这两个 directive 就该删掉 —— 它们不会帮你解决问题,只会增加维护成本。
strict_types 不检查变量赋值,只校验函数调用
它管的是「函数参数传入时」和「函数返回值返回时」的类型匹配,不是变量声明或赋值过程。比如:
$x = "123"; $x = (int)$x; // 合法,strict_types 不干预
但下面这个会炸:
declare(strict_types=1);
function foo(int $n) { return $n; }
foo("123"); // TypeError: Argument #1 must be of type int, string given
注意边界:
- 类属性类型(
public int $count;)、构造函数参数、setter 方法参数,这些都受 strict_types 影响 - 数组键、foreach 变量、引用赋值、类型断言(
$x is int)都不走 strict_types 校验路径 - 错误容易发生在「调用第三方库函数」时:你开了 strict,但对方函数没声明类型,或声明了但没开 strict,行为就不可控
真正容易被忽略的一点:strict_types 对 trait 中的方法声明也生效,但 trait 本身不带 declare 指令 —— 所以用 trait 的类文件必须自己声明,否则 trait 方法调用不校验。



















