php 8.5 不支持 clone with 语法;当前需手动实现 with() 方法,通过 new static(...) 和 get_object_vars() 克隆并覆盖属性,兼顾兼容性与可控性。

PHP 8.5 中 clone 不支持 with 语法
PHP 8.5 并没有引入 with 关键字用于对象克隆。你看到的 clone with 是误传,或者混淆了其他语言(如 Kotlin、Rust)或 PHP RFC 提案(比如曾被讨论但未合入的 “Clone with properties” RFC)。目前 PHP 原生 clone 只能复制对象,不能在一行中同时指定新属性值。
替代方案:用构造函数 + 数组解包模拟 clone with
最贴近需求的做法是手动实现一个可复用的 with 风格方法,本质是“克隆后批量赋值”。它不依赖语言特性,兼容 PHP 8.0+,且可控性强。
常见错误现象:clone $obj; $obj->prop = $newVal; 看似简单,但对嵌套对象、只读属性、类型约束或魔术方法(__set)不友好,容易漏改或触发意外副作用。
- 推荐在类中定义
with()方法,返回新实例(非修改原对象) - 使用
new static(...)+get_object_vars($this)获取当前状态,再用数组合并覆盖指定字段 - 注意:若属性含私有/受保护成员,
get_object_vars()仅返回可访问字段;需配合反射或显式白名单 - 示例:
public function with(array $changes): self { $data = get_object_vars($this); $data = array_merge($data, $changes); return new static(...array_values($data)); }为什么不用
__clone+ 参数?__clone()是魔术方法,PHP 调用时无参数,无法接收“要修改哪些属性”。强行在其中读取外部变量会破坏封装,也违背克隆语义。立即学习“PHP免费学习笔记(深入)”;
-
__clone()只适合做深拷贝、资源重置等固定逻辑,不适合动态属性覆盖 - 试图在
__clone()里检查$GLOBALS或闭包上下文,属于反模式,调试困难、不可测试 - 如果真需要运行时控制克隆行为,应把逻辑上提到调用方,而非塞进
__clone
性能与兼容性提醒
自定义
with()方法比原生clone多一次构造和数组操作,但差异极小(纳秒级),除非高频循环调用(>10 万次/秒),否则无需优化。- PHP 8.2+ 支持只读类(
readonly class),此时with()必须返回新实例,不能尝试修改原对象属性 - 若类有复杂初始化逻辑(如连接数据库、加载配置),
with()应复用已有构造流程,避免重复开销 - 别忘了类型声明:参数
array $changes和返回self能让 IDE 和静态分析更准
真正麻烦的是属性访问控制和继承关系——父类私有属性无法被子类
with()触达,这时候要么暴露 getter/setter,要么用反射兜底,但后者会让代码变脆。 -











