天天看点

【1-1】PHP中的引用与赋值 前提须知:

前提须知:

  1. COW机制:Copy-on-Write,写入时才真正复制一份内存进行修改
  2. 引用:用不同的名字访问同一个变量内容(符号:&)
  3. zval的容器:所有的php变量都放在了zval的容器中,一个zval变量容器包含:类型、值、is_ref(代表这个"容器"是否被引用,1 引用 0 默认)、refcount(代表有多少变量指向这个"容器")
  4. xdebug_debug_zval():通过调用函数显示"refcount"和"is_ref"的值
  5. memory_get_usage():返回分配给 PHP 的内存量说明 

COW机制--对应例子1:

<?php
$a = range(0,9999);                //赋值变量$a
var_dump(memory_get_usage());      //打印已使用的内存
$b = $a;                           //赋值变量$b=$a,不会分配内存,因为没有对内容进行写入操作
var_dump(memory_get_usage());      //打印的内存不会明显发生改变
$a = range(0,9999);                //对变量$a重新赋值
var_dump(memory_get_usage());      //内存发生明显变化


//输出结果:
int 5391568
int 5391568
int 6257216
           

COW机制--对应例子2:

<?php

// zval变量容器
$a = 1;
xdebug_debug_zval('a');

// 定义变量b,把a的值赋值给b
$b = $a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

// 修改a
$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

//输出结果:
a:
(refcount=1, is_ref=0),int 1
a:
(refcount=2, is_ref=0),int 1
b:
(refcount=2, is_ref=0),int 1
a:
(refcount=1, is_ref=0),int 2
b:
(refcount=1, is_ref=0),int 1
           

引用--对应例子1

<?php
$a = range(0,9999);                //赋值变量$a
var_dump(memory_get_usage());      //打印已使用的内存
$b = &$a;                          //把$a的地址给$b,$a和$b指向同一个内存空间
var_dump(memory_get_usage());      //打印的内存不会明显发生改变
$a = range(0,9999);                //只是改调了空间值,$a和$b指向的都是修改后的值
var_dump(memory_get_usage());      //打印的内存还是不会明显发生改变


//输出结果:
int 5391568
int 5391568
int 5391544
           

 引用--对应例子2

<?php

// zval变量容器
$a = 1;
xdebug_debug_zval('a');

// 定义变量b,把a的值赋值给b
$b = &$a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

// 修改a
$a = 2;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

//输出结果:
a:
(refcount=1, is_ref=0),int 1
a:
(refcount=2, is_ref=1),int 1
b:
(refcount=2, is_ref=1),int 1
a:
(refcount=2, is_ref=1),int 2
b:
(refcount=2, is_ref=1),int 2
           

  引用--对应例子3

<?php
// unset 只会取消引用,不会销毁空间
$a = 1;
$b = &$a;
unset($b);
echo $a. "\n"; //还是会输出1

//输出内容:
1
           

   引用--对应例子4

<?php

// 对象本身就是引用传递
class Demo
{
    public $name = "demo1";
}

$d1 = new Demo;
xdebug_debug_zval('d1');

$d2 = $d1;
xdebug_debug_zval('d1');
xdebug_debug_zval('d2');

$d2->name = "demo2";
xdebug_debug_zval('d1');
xdebug_debug_zval('d2');

//输出结果:
d1:
(refcount=1, is_ref=0),
object(app\index\controller\Demo)[183]
  public 'name' => (refcount=1, is_ref=0),string 'demo1' (length=5)
d1:
(refcount=2, is_ref=0),
object(app\index\controller\Demo)[183]
  public 'name' => (refcount=1, is_ref=0),string 'demo1' (length=5)
d2:
(refcount=2, is_ref=0),
object(app\index\controller\Demo)[183]
  public 'name' => (refcount=1, is_ref=0),string 'demo1' (length=5)
d1:
(refcount=2, is_ref=0),
object(app\index\controller\Demo)[183]
  public 'name' => (refcount=1, is_ref=0),string 'demo2' (length=5)
d2:
(refcount=2, is_ref=0),
object(app\index\controller\Demo)[183]
  public 'name' => (refcount=1, is_ref=0),string 'demo2' (length=5)
           

   总结例子

<?php

/**
 * 写出如下程序的输出结果
 * <?php
 *
 * $data = ['a', 'b', 'c'];
 *
 * foreach($data as $key => $val)
 * {
 *      $val = &$data[$key];
 * }
 * 程序运行时,每一次循环结束后变量$data的值是什么?请解释
 * 程序执行完成后,变量$data的值是什么?请解释
 */

$data = ['a', 'b', 'c'];

foreach ($data as $key=>$val)
{
    $val = &$data[$key];
    var_dump($data);
}

var_dump($data);

//输出结果:

array (size=3)
  0 => &string 'a' (length=1)
  1 => string 'b' (length=1)
  2 => string 'c' (length=1)
array (size=3)
  0 => string 'b' (length=1)
  1 => &string 'b' (length=1)
  2 => string 'c' (length=1)
array (size=3)
  0 => string 'b' (length=1)
  1 => string 'c' (length=1)
  2 => &string 'c' (length=1)
array (size=3)
  0 => string 'b' (length=1)
  1 => string 'c' (length=1)
  2 => &string 'c' (length=1)
           

附加clone的用法

由于对象本身就是引用传递,

假设$obj1和$obj2是两个对象,使用$obj2=$obj1这样的方法复制出来的对象是相关联的

如果想让复制的对象$obj2修改属性时不会改变$obj1的属性,可以用$obj2=clone $obj1; 

 如果还希望在复制的同时,目标对象的某些属性与源对象的不同,可以在类里面定义一个__clone()方法,在这个方法中完成为目标对象的属性赋新值。

<?php

class demoClone{
    private $id,$name;
    public function __construct($id=0,$name=''){
        $this->name=$name;
        $this->id=$id;
    }
    public function get_id(){
        return $this->id;
    }
    public function get_name(){
        return $this->name;
    }

    /*当没有__clone和有__clone是有区别的*/
    public function __clone(){
        $this->id=$this->id+1;
        $this->name='FJ';

    }

}

 
$A = new demoClone(10,'A','UK');
echo '克隆之前的对象:';
echo 'id='.$A->get_id();
echo 'name='.$A->get_name();
echo "\n";
 
 
$B = clone $A;
echo '克隆过后的对象:';
echo 'id='.$A->get_id();
echo 'name='.$A->get_name();
echo "\n";
 
echo '克隆过后的对象属性:';
echo 'id='.$B->get_id();
echo 'name='.$B->get_name();


//输出结果:
//当没有__clone
克隆之前的对象:id=10name=HEHE
克隆过后的对象:id=10name=HEHE
克隆过后的对象属性:id=10name=HEHE

//当有__clone
克隆之前的对象:id=10name=HEHE
克隆过后的对象:id=10name=HEHE
克隆过后的对象属性:id=11name=FJ
           

内容是对慕课网视频教程《360大牛带你横扫PHP职场 全面解读PHP面试》的看后总结记录