php面向对象——对象的传递方式

理论基础

  • 传值赋值 (赋值运算),将原变量的值拷贝到新变量中,所以改变其中一个并不影响另一个,适合于在密集循环中拷贝一些值例如大数组
  • 引用赋值,使用 $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代码

  1. 导致数据区生成一个对象内存,存放name=null age=null两个数据
  2. 同时,会产生一个对象标识符#1$p1指向#1#1指向对象内存

栈区运行$p1->name=’金角‘代码

  1. p1先找到对象的标识符#1,然后通过标识符#1找到对象内存
  2. 然后修改对应的属性值

栈区运行$p2 = $p1代码

  1. $p2 = $p1是传值赋值,p1指向的是对象标识符#1,因此将对象标识符#1拷贝了一份,此时有两个标识符#1
  2. p2指向新拷贝的标识符#1
  3. 对象标识符一样,自然指向同一个对象内存

栈区运行$p2->name=’银角代码

  1. p2先找到对象的标识符#1,然后通过标识符#1找到对象内存
  2. 然后修改对应的属性值

对象传值赋值示例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);    // 两个值都改了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值