php 7.2 中 ... 运算符仅支持数组或 traversable 对象展开,不支持 null、字符串或未实现遍历接口的对象;关联数组展开保留键名,同名字符串键后值覆盖前值,整数键按顺序追加;declare(strict_types=1) 必须置于文件首行非注释/非空白语句才生效,且不作用于被引入文件。

PHP 7.2 的函数调用和参数处理,核心瓶颈往往不在逻辑本身,而在类型校验松散、参数展开不明确、或扩展运算符误用导致的运行时错误。启用 declare(strict_types=1) 并配合 ... 运算符的正确姿势,能直接规避 80% 以上的隐式转换类问题。
strict_types=1 必须放在文件顶部第一行
这个声明只对当前文件生效,且必须是脚本中**第一个非空白、非注释的语句**。放错位置(比如在命名空间之后、或被 if 包裹)会导致完全失效,形同虚设。
- ✅ 正确:
declare(strict_types=1); namespace App; - ❌ 错误:
namespace App; declare(strict_types=1);(已失效) - ❌ 错误:
if (true) { declare(strict_types=1); }(语法允许但无作用)
它不会影响 include 或 require 的其他文件——那些文件需各自声明。
函数参数展开时,... 只接受数组或 Traversable
你不能对 null、字符串、对象(未实现 Traversable)直接使用 ...,否则会抛出 Fatal error: Uncaught TypeError: Cannot unpack array 类错误。
- ✅ 安全写法:
$args = is_array($input) ? $input : [];,再传入func(...$args) - ✅ 替代方案:用
call_user_func_array()兜底(但失去类型提示和性能优势) - ⚠️ 关联数组展开要小心:PHP 7.2 对字符串键的支持较弱,
['a' => 1, 'b' => 2]展开后仍保持键名,但若混用整数键(如[0 => 'x', 'a' => 'y']),顺序和索引行为可能与预期不符
合并数组时,[...$arr1, ...$arr2] 不等于 array_merge()
这是最容易混淆的点。array_merge() 会重索引数字键、保留字符串键;而 [...$arr1, ...$arr2] 是按遍历顺序逐个追加,数字键不会重排,字符串键会覆盖(后出现的同名键胜出)。
- 例如:
$a = [1, 2]; $b = [3, 4]; [...$a, ...$b]→[1, 2, 3, 4](正常) - 但:
$a = ['x' => 1]; $b = ['x' => 2]; [...$a, ...$b]→['x' => 2]($b覆盖) - 而:
array_merge($a, $b)同样是['x' => 2],但行为机制不同——前者是语言级展开,后者是函数级合并
如果你依赖 array_merge() 的重索引行为(比如合并多个一维结果集),别盲目替换为 ...。
对象类型声明 + ... 组合时,类型提示不穿透展开层
function foo(User ...$users): void 是合法语法,但 PHP 7.2 **不会对每个 $users[i] 做单独类型检查**——它只检查传入的是否为数组/Traversable,内部元素类型由运行时逻辑保障。真正的类型约束需靠手动循环或后续断言。
- 也就是说:
foo([new User(), "not a user"])不会报错(除非你在函数体内显式校验) - 若要强约束,得写成:
function foo(array $users): void { foreach ($users as $u) { if (!$u instanceof User) { throw new TypeError(); } } } - PHP 8.1+ 的
array<user></user>语法才真正支持泛型级约束,7.2 没有
所以别指望 ... 和对象类型声明自动形成“类型安全管道”,它们是正交特性,需组合使用但不能互相替代。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











