0

0

PHP 中对象赋值默认为引用传递:理解与正确处理对象拷贝

霞舞

霞舞

发布时间:2026-01-02 13:37:02

|

223人浏览过

|

来源于php中文网

原创

php 中对象赋值默认为引用传递:理解与正确处理对象拷贝

php 中对象赋值默认为引用传递:理解与正确处理对象拷贝

在 PHP 中,对象(object)与其他标量类型(如 int、string、array)有本质区别对象变量不直接存储对象数据,而是持有一个指向 Zend 引擎内部对象存储区的标识符(object handle)。因此,当你执行 $ref = $listOfTest[4]; 时,并未复制对象本身,而是让 $ref 指向与 $listOfTest[4] 完全相同的内存对象实例。后续对 $ref 或其属性(如调用 SetTest(5))的任何修改,都会直接影响原始数组中的对应对象——这正是示例中输出从 2-4-6 变为 2-5-6 的根本原因。

这种行为是 PHP 5.0+ 的设计特性(自 PHP 5 起,对象默认按“引用语义”传递),并非 bug,但常被误认为“意外引用”。它提升了性能(避免无谓深拷贝),但也要求开发者明确区分“共享对象”与“独立副本”的使用场景。

✅ 正确解决方案:显式克隆(clone)

当需要独立副本时,必须显式调用 clone 关键字。注意:clone 执行的是浅拷贝(shallow copy),即仅复制对象自身及其直接属性,若属性中包含其他对象,则这些嵌套对象仍被共享(除非在 __clone() 魔术方法中手动深拷贝):

VIVA
VIVA

一个免费的AI创意视觉设计平台

下载
function getNewList(TestBase $ref): array
{
    // ✅ 正确:为每个位置创建独立对象副本
    $newlist = [
        3 => clone $ref,  // 新对象,初始状态同 $ref
        5 => clone $ref   // 另一个新对象,与上一个及 $ref 彼此隔离
    ];
    $newlist[3]->SetTest(3);
    $newlist[5]->SetTest(5);
    return $newlist;
}

// 使用前确保传入的是原始对象,而非已引用的变量
$ref = $listOfTest[4]; // 这里仍是引用,但 getNewList 内部会 clone
$newList = getNewList($ref);

// ✅ 输出保持为:2, 4, 6 —— 原数组未被修改
foreach ($listOfTest as $test) {
    echo $test->GetTest() . '
'; }

⚠️ 常见误区与注意事项

  • & 引用操作符不能解决对象共享问题:$ref = &$listOfTest[4]; 仅让 $ref 成为 $listOfTest[4] 的别名,两者仍指向同一对象,无法避免副作用。
  • 函数参数传递也是引用语义:即使参数未声明为 &$param,对象传入函数时默认仍是“按引用语义”(即共享实例),因此 getNewList($ref) 中的 $ref 和外部 $listOfTest[4] 本质相同。
  • 避免全局性“自动克隆”优化:不要试图通过重写赋值逻辑或拦截器来强制所有对象赋值自动 clone——这违背语言约定、损害可读性,且无法覆盖所有边界(如 array_merge、json_decode(..., false) 等)。
  • 大型系统实践建议
    • 在领域模型中,对不可变对象(Immutable Object)建模:构造后禁止修改,所有“变更”返回新实例(类似 Laravel 的 Carbon::copy() 或 DateTimeImmutable);
    • 对需频繁复制的复杂对象,实现健壮的 __clone() 方法,处理资源句柄、闭包或嵌套对象;
    • 使用工厂类(Factory)或构建器(Builder)集中管理对象创建与克隆逻辑,提升一致性与可测试性。

总之,PHP 的对象引用语义是明确且一致的。与其规避,不如拥抱——通过 clone 显式表达“我需要一份独立副本”,既符合语言规范,也使代码意图清晰、行为可预测。

立即学习PHP免费学习笔记(深入)”;

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2027

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1362

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1270

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

948

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1402

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1231

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1440

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1303

2023.11.13

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

74

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 8.2万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 6.9万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号