您的位置:首页 > 编程语言 > PHP开发

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

2020-06-29 04:51 926 查看

理论基础

  • 传值赋值 (赋值运算),将原变量的值拷贝到新变量中,所以改变其中一个并不影响另一个,适合于在密集循环中拷贝一些值例如大数组
  • 引用赋值,使用
    $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);    // 两个值都改了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: