理论基础
- 传值赋值 (赋值运算),将原变量的值拷贝到新变量中,所以改变其中一个并不影响另一个,适合于在密集循环中拷贝一些值例如大数组
- 引用赋值,使用
$var= &$othervar
语法,引用赋值意味着两个变量指向了同一个数据,没有拷贝任何东西 - 在php5中,一个对象变量并不是保存整个对象的值,而是保存一个对象标识符来访问真正的对象内容,因此,当对象作为参数传递,作为结果返回,或者赋值给另外一个变量,另外一个变量跟原来的不是引用的关系,只是他们都保存着同一个标识符的拷贝,这个标识符指向同一个对象的真正内容
对象的传值赋值
对象的传值赋值结论
当我们把一个对象赋给另一个对象时即$p2 = $p1
,是值拷贝(传值赋值),但是拷贝的不是数据本身,而是对象标识符
对象传值赋值示例1
class Person{
public $name;
public $age;
}
$p1 = new Person();
$p1->name = '金角大王';
$p1->age = 300;
$p2 = $p1;
$p2->name = '银角大王';
echo $p1->name,'<br>';
echo $p2->name,'<br>';
var_dump($p1,$p2);
示例1 内存图
- 内存中有代码区,栈区,数据区
- 代码区负责编译,所有要执行的代码必须先被加载到代码区
- 栈区负责运行代码,代码区的代码被逐条扔进栈区进行运行
- 数据区负责存放数据
示例1 内存流程详解
栈区运行$p1=new Person
代码
- 导致数据区生成一个对象内存,存放
name=null age=null
两个数据 - 同时,会产生一个对象标识符
#1
,$p1
指向#1
,#1
指向对象内存
栈区运行$p1->name=’金角‘
代码
p1
先找到对象的标识符#1
,然后通过标识符#1
找到对象内存- 然后修改对应的属性值
栈区运行$p2 = $p1
代码
$p2 = $p1
是传值赋值,p1
指向的是对象标识符#1
,因此将对象标识符#1
拷贝了一份,此时有两个标识符#1
p2
指向新拷贝的标识符#1
- 对象标识符一样,自然指向同一个对象内存
栈区运行$p2->name=’银角
代码
p2
先找到对象的标识符#1
,然后通过标识符#1
找到对象内存- 然后修改对应的属性值
对象传值赋值示例2
class Person{
public $name;
}
$p1 = new Person();
$p1->name = 'aa';
$p2 = $p1;
$p2 = 'abc';
echo $p1->name,'<br>'; // '银角大王'
echo $p2->name,'<br>'; // 自然报错,p2指向的是字符串
echo $p2; // 'abc'
示例2 内存图
对象的引用赋值
对象的引用赋值结论
当我们把一个对象赋给另一个对象时$p2 = &$p1
,也是值拷贝(传值赋值),但是拷贝的不是数据本身,而是对象标识符
对象引用赋值示例1
class Person{
public $name;
}
$p1 = new Person();
$p1->name = 'aa';
$p2 = &$p1; // 引用赋值 p1 p2指向同一个标识符#1
$p2 = 'abc';
//echo $p1->name,'<br>'; // 报错,p1指向的是字符串,因#1标识符已经改为了字符串
//echo $p2->name,'<br>'; // 报错,p2指向的是字符串
var_dump($p1,$p2); // string 'abc' string 'abc'
示例1 内存图
对象引用赋值示例2
class Person{
public $name;
}
$p1 = new Person();
$p1->name = 'aa';
$p2 = &$p1;
$p2->name = 'abc';
echo $p1->name,'<br>'; // abc
echo $p2->name,'<br>'; // abc
var_dump($p1,$p2);
示例2 内存图
对象引用赋值示例3
class Person{
public $name;
}
$p1 = new Person();
$p1->name = 'aa';
$p2 = &$p1;
$p2->name = 'abc';
unset($p2);
echo $p1->name,'<br>'; // abc
echo $p2->name,'<br>'; // 未定义变量:p2
var_dump($p1,$p2); // object(Person)[1] null
示例3 内存图
注意:unset() 销毁的是变量,并不是内存
对象的克隆
class Person{
private $name;
public function __construct($name){
$this->name = $name;
}
}
$p1 = new Person('aa');
$p2 = clone $p1;
if ($p1 == $p2){
echo '$p1==$p2<br>';
}
var_dump($p1,$p2); // object(Person)[1] object(Person)[2]
对象的比较
注意是对象的比较,非对象不适用
- 当使用比较运算符
==
比较两个对象变量时,比较的原则是:如果两个对象的属性和属性值都相等,而且两个对象是同一个类的实例,那么这两个对象变量相等 - 如果使用全等运算符
===
,在==
的基础上,这两个对象变量一定要指向堆内存中同一个内存空间
对象传值赋值
class Person{
private $name;
public function __construct($name){
$this->name = $name;
}
}
$p1 = new Person('aa');
$p2 = $p1;
if ($p1 === $p2){
echo '$p1===$p2<br>';
}
var_dump($p1,$p2); // object(Person)[1] object(Person)[1]
对象引用赋值
class Person{
private $name;
public function __construct($name){
$this->name = $name;
}
}
$p1 = new Person('aa');
$p2 = &$p1;
if ($p1 === $p2){
echo '$p1===$p2<br>';
}
var_dump($p1,$p2); // object(Person)[1] object(Person)[1]
实例化新对象
class Person{
private $name;
public function __construct($name){
$this->name = $name;
}
}
$p1 = new Person('aa');
$p2 = new Person('aa');
if ($p1 == $p2){
echo '$p1==$p2<br>';
}
var_dump($p1,$p2); // object(Person)[1] object(Person)[2]
克隆对象
class Person{
private $name;
public function __construct($name){
$this->name = $name;
}
}
$p1 = new Person('aa');
$p2 = clone $p1;
if ($p1 == $p2){
echo '$p1==$p2<br>';
}
var_dump($p1,$p2); // object(Person)[1] object(Person)[2]
克隆对象和实例化新对象比较
需求: 将对象整体复制一份,两种方法都能实现
- 实例化新对象比较low,麻烦,需要传值,且p1如果修改属性值的话就不一样了
- clone不仅完全一样,且clone可以配合__clone魔术方法,在clone完成时,自动调用__clone魔术方法,修改属性值
class Person{
private $name;
public function __construct($name){
$this->name = $name;
}
// 在clone完成时,__clone魔术方法自动被调用,可以用于修改克隆来的属性值
public function __clone(){
$this->name = 'abc';
}
}
$p1 = new Person('aa');
$p2 = clone $p1;
var_dump($p1,$p2); // object(Person)[1] object(Person)[2]
如何阻止对象克隆
修改__clone魔术方法为private,可以阻止对象被克隆
class Person{
private $name;
public function __construct($name){
$this->name = $name;
}
// 修改__clone魔术方法为private,可以阻止对象被克隆
private function __clone(){}
}
$p1 = new Person('aa');
$p2 = clone $p1; // 报错
非对象的传递方式
非对象是没有对象标识符的,标识符为对象特有的
非对象传值赋值
$a = 'hello';
$b = $a;
if ($a===$b){
echo '$a===$b'; // $a===$b
}
非对象引用赋值
$a = 'hello';
$b = &$a;
延伸
class Person{
public $name;
}
$p1 = new Person();
$a = [1,2,5,['zz',$p1]];
$b = $a;
if ($a===$b){
echo '$a===$b'; // $a===$b
}
$b[3][1]->name = '唐僧';
var_dump($a,$b); // 两个值都改了