一篇搞懂php的引用

作者: Monkey_zhou | 来源:发表于2018-09-22 15:17 被阅读8次
    image

    引用变量的解释

    1. 引用是什么?
      再PHP中引用意味着用不同的名字访问同一个变量的内容;
      注意: 在PHP中,变量名和变量内容是不一样的,因此同样的内容可以有不同的名字。最接近的比喻是`Unix` 的 `文件名` 和 `文件本身` -- 变量名是目录条目,而变量内容则是文件本身,引用可以被看做是`Unix`文件系统的 `硬链接` ;
      example1.php
    <?php
     $var = "foo";
        $ref1 =& $var; // 引用 $var 的内存空间
        //安装debug扩展,可以使用此方法打印
        xdebug_debug_zval('var');//(refcount=2, is_ref=1)string 'foo' (length=3)
       
        echo $ref1; // >Notice:  Undefined variable: ref1
        echo $var; // >foo
    ?>
    
    1. 引用不是什么?
      引用不是指针 , 这意味着一下的结构不会产生预期的效果
    <?php
    function foo(&$var)
    {
        $var = &$GLOBALS["baz"];
    }
    foo($bar);
    ?>
    

    这将使 foo 函数中的 $var 变量在函数调用时和 $bar 绑定在一起,但接着又被重新绑定到了 $GLOBALS["baz"] 上面。不可能通过引用机制将 $bar 在函数调用范围内绑定到别的变量上面,因为在函数 foo 中并没有变量 $bar(它被表示为 $var,但是 $var 只有变量内容而没有调用符号表中的名字到值的绑定)。
    example2.php

    <?php
    $ref = [1,2,3];
    $c = count($ref);
    $foo = ['A'];
     
    for($i=0;$i<$c;$i++)
        $foo[] =& $ref[$i];
    
    print_r($foo);
    print_r($ref);
    
    $ref = [4,5,6];
    
    print_r($foo);
    print_r($ref);
    ?>
    /* 打印结果:
    Array
    (
        [0] => A
        [1] => 1
        [2] => 2
        [3] => 3
    )
    Array
    (
        [0] => 1
        [1] => 2
        [2] => 3
    )
    Array
    (
        [0] => A
        [1] => 1
        [2] => 2
        [3] => 3
    )
    Array
    (
        [0] => 4
        [1] => 5
        [2] => 6
    )
    */
    

    注意example2.php$ref 经历了 Copy-on-Write 缩写为 COW 写时复制

    1. 引用做什么?
      PHP的引用允许用两个变量来指向同一个内容
      example3.php
    <?php
    $a =& $b;
    ?>
    

    这意味着 $a$b 指向了同一个变量。
    注意:
    a> $a$b 在这里是完全相同的,这并不是 $a 指向了 $b 或者相反,而是 $a$b 指向了同一个地方。
    b> 如果具有引用的数组被拷贝,其值不会解除引用。对于数组传值给函数也是如此。
    c> 如果对一个未定义的变量进行引用赋值、引用参数传递或引用返回,则会自动创建该变量。

    example4.php

    <?php
    // 对未定义的变量使用引用
    function foo(&$var) { }
    foo($a); // 创建 $a,并用 null 赋值 
    
    $b = array();
    foo($b['b']);
    var_dump(array_key_exists('b', $b)); // bool(true)
    
    $c = new StdClass;
    foo($c->d);
    var_dump(property_exists($c, 'd')); // bool(true)
    ?>
    

    d>同样的语法可以用在函数中,它返回引用,以及用在 new 运算符中:

    example4.php

    ?>
    $bar = &new fooclass();
    $fll = &find_var($bar);
    ?>
    

    自 PHP 5 起,自动返回引用,因此在此使用 =& 已经过时了并且会产生 E_STRICT 级别的消息。
    e> 不用 & 运算符导致对象生成了一个拷贝。如果在类中用 $this,它将作用于该类当前的实例。
    没有用 & 的赋值将拷贝这个实例(例如对象)并且 $this 将作用于这个拷贝上,这并不总是想要的结果。
    由于性能和内存消耗的问题,通常只想工作在一个实例上面。
    尽管可以用 @ 运算符来抑制构造函数中的任何错误信息,例如用 @new,但用 &new 语句时这不起效果。这是 Zend 引擎的一个限制并且会导致一个解析错误。
    f> 注意:如果在一个函数内部给一个声明为 global 的变量赋于一个引用,该引用只在函数内部可见。可以通过使用 $GLOBALS 数组避免这一点。

    example5.php

    <?php
    $var1 = "Example variable";
    $var2 = "";
    
    function global_references($use_globals)
    {
        global $var1, $var2;
        if (!$use_globals) {
            $var2 =& $var1; // visible only inside the function
        } else {
            $GLOBALS["var2"] =& $var1; // visible also in global context
        }
    }
    
    global_references(false);
    echo "var2 is set to '$var2'\n"; // var2 is set to ''
    global_references(true);
    echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable'
    ?>
    

    global $var; 当成是 $var =& $GLOBALS['var']; 的简写。从而将其它引用赋给 $var 只改变了本地变量的引用。

    example6.php

    <?php
    $ref = 0;
    $row =& $ref;
    foreach (array(1, 2, 3) as $row) {
        // do something
    }
    echo $ref; // 3  数组中的最后一个元素
    ?>
    
    1. 引用的其他用途:
      引用做的第二件事是用引用传递变量。这是通过在函数内建立一个本地变量并且该变量在呼叫范围内引用了同一个内容来实现的
      example7.php
    <?php
    function foo(&$var)
    {
        $var++;
    }
    
    $a=5;
    foo($a);
    ?>
    

    将使 $a 变成 6。这是因为在 foo 函数中变量 $var 指向了和 $a 指向的同一个内容。更多详细解释见引用传递

    1. 引用传递
      可以将一个变量通过引用传递给函数,这样该函数就可以修改其参数的值;
      example8.php
    <?php
    function foo(&$var)
    {
        $var++;
    }
    
    $a=5;
    foo($a);
    // $a is 6 here
    ?>
    

    注意:
    在函数调用时没有引用符号——只有 函数定义 中有。光是函数定义就足够使参数通过引用来正确传递了。在最近版本的 PHP 中如果把 & 用在 foo(&$a); 中会得到一条警告说"Call-time pass-by-reference"已经过时了。
    以下内容可以通过引用传递:
    1> 变量,例如 foo($a)
    2> New 语句,例如 foo(new foobar())
    3> 从函数中返回的引用;

    example9.php

    //以下内容可以通过引用传递:
    <?php
    function &bar()
    {
        $a = 5;
        return $a;
    }
    foo(bar());
    ?>
    
    1. 引用返回
      引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。不要用返回引用来增加性能,引擎足够聪明来自己进行优化。仅在有合理的技术原因时才返回引用!

    example10.php

    <?php
    class foo {
        public $value = 42;
    
        public function &getValue() {
            return $this->value;
        }
    }
    
    $obj = new foo;
    $myValue = &$obj->getValue(); //42
    $obj->value = 2;
    echo $myValue;                // 打印 $obj->value,  2.
    ?>
    

    本例中 getValue 函数所返回的对象的属性将被赋值,而不是拷贝,就和没有用引用语法一样。

    注意:
    参数传递 不同,这里必须在 两个地方 都用 & 符号—— 指出返回的是一个引用,而不是通常的一个拷贝, 同样也指出 $myValue 是作为引用的绑定,而不是通常的赋值。

    如果试图这样从函数返回引用:return ($this->value); ,这将 不会起作用因为在试图返回一个表达式的结果而不是一个引用的变量
    只能从函数返回引用变量 ——没别的方法。
    如果代码试图返回一个动态表达式或 new 运算符的结果,自 PHP 4.4.0 和 PHP 5.1.0 起会发出一条 E_NOTICE 错误。

    1. 取消引用
      当 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。
    <?php
    $a = 1;
    $b =& $a;
    unset($a);
    ?>
    

    不会 unset $b,只是 $a
    再拿这个和 Unixunlink 调用来类比一下可能有助于理解。
    7.引用定位
    许多 PHP 的语法结构是通过引用机制实现的,所以上述有关引用绑定的一切也都适用于这些结构。一些结构,例如引用传递和返回,已经在上面提到了。
    其他的引用结构有:
    1> global :当用 global $var 声明一个变量时实际上建立了一个到全局变量的引用。

    <?php
    $var =& $GLOBALS["var"];
    ?>
    

    这意味着,例如,unset $var 不会 unset 全局变量。
    2> $this :在一个对象的方法中,$this 永远是调用它的对象的引用。

    以上就是引用的全部内容;

    相关题目:

    <?php
    /**
     * 每次循环的结果是什么?最终程序执行完的结果是什么?为什么?
     */
    $data = ['a', 'b', 'c'];
    foreach ($data as $key => $val){
        $val = &$data[$key];
        var_dump($data);
    }
    
    var_dump($data);
    ?>
    

    相关文章

      网友评论

        本文标题:一篇搞懂php的引用

        本文链接:https://www.haomeiwen.com/subject/sytxoftx.html