在 PHP 和 JavaScript 中(或许还有其余语言),变量内所保存的值分为 基本类型值
和 引用类型值
。函数
$obj = new stdClass;
若一个变量是一个对象,那么该变量保存的就是一个引用类型的值,即变量中实际保存的是堆内存中对象的地址,而不是对象的实体;若变量为其余类型,则保存的是基本类型值,而不是引用地址。这一点须要特别注意,由于咱们可能会遇到以下几种状况,不清楚原理可能致使出错。code
$obj_1 = new stdClass; $obj_2 = $obj_1; $obj_1->name = 'Xavier'; var_dump($obj_1->name, $obj_2->name); var_dump($obj_1, $obj_2);
输出:对象
string(6) "Xavier" string(6) "Xavier" object(stdClass)#1 (1) { ["name"]=> string(6) "Xavier" } object(stdClass)#1 (1) { ["name"]=> string(6) "Xavier" }
咱们发现 obj_2
的 name
也发生的改变,缘由是 obj_1
和 obj_2
指向同一个对象 #1
,由于在第二行中,咱们将 obj_1
所指向的对象的地址赋给了 obj_2
。ip
咱们来看这段代码:内存
function setName($obj) { $obj->name = 'Xavier'; } $person = new stdClass; setName($person); var_dump($person->name); // 输出 string(6) "Xavier"
若变量为一个对象,那么当它做为参数传递给一个函数时,一样,传递的是一个对象地址,而不是拷贝了一个新的对象实体给参数 $obj
。这样,函数内部并无 return 新的东西出来但改变了外部的状态
的这种状况就变得好理解了。string
接下来,请看这段代码:io
function setName($obj) { $obj->name = 'Xavier'; $obj = new stdClass; $obj->name = 'Zhao'; } $person = new stdClass; setName($person); var_dump($person->name); // 输出了 string(6) "Xavier" 而不是 string(6) "Zhao"
最后的输出结果可能会让不少人会疑惑,他们的思惟多是这样的:function
person
对象的引用地址传递给 obj参数
obj
的引用地址,我将函数外部对象的 name
属性设置成了 "Xavier"
obj
,既然 obj
为函数外部对象的引用,那么外部对象也必定变为了这个新的对象name
属性 "zhao"
,嗯,这样外部对象的 name
必定也变成了 "zhao"
若是你想的和上方相同,那可就大错特错了,缘由在于对传递参数的过程的错误理解。变量
首先,咱们应该明白,将一个变量做为参数传递给函数
能够理解为 将那个变量保存的值 复制一份给 函数的参数(参数即函数范围的局部变量)
。当函数执行时,外部变量
和 函数参数(局部变量)
是同时存在于内存中的,而且二者是相互独立的,虽然二者所保存的值是相同的;函数参数(局部变量)
会在函数执行完毕后被销毁。原理
明白了上述原理,那么咱们从新来看那段代码:
obj
变量在函数内第一行保存的是函数外部 person
变量所保存的值,也就是外部对象的地址obj
变量所保存的值变成了新建立的对象的地址,obj
的指向发生了改变,而原来的外部对象依旧存在而且只被 person
一个变量引用,因此在第三行的行为并无影响到 person
所指向的那个对象。新建立的对象在函数执行以后被销毁。因此有代码中注释的输出结果。