• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

彻底搞明白PHP的中引用的概念

php 搞代码 3年前 (2022-02-28) 12次浏览 已收录 0个评论
文章目录[隐藏]

之前咱们其实曾经有过几篇文章讲过援用方面的问题,这次咱们来全面的梳理一下援用在PHP到底是怎么回事,它和C中的指针有什么不同,在应用的时候要留神些什么。

什么是援用?

在 PHP 中援用意味着用不同的名字拜访同一个变量内容。它不是C的指针,保留的并不是内存地址,无奈进行指针运算。援用只是符号表的别名。就像 Unix 零碎中的硬链接, Windows 零碎中的快捷方式。

下面是官网手册中的原文,怎么说呢,援用其实和咱们印象中的C外面的指针并不是雷同的概念。指针是针对实在内存的操作,援用是针对指向这个内存的符号表的操作。还是从操作系统的快捷方式来说,快捷方式是能够删的,这就是PHP的援用。而C不仅删了快捷方式,还把原文件也给删了,这就是C的指针操作。

<code class="php">// 援用不是指针
$a = 1;
$b = &$a;
echo $a, '===', $b, PHP_EOL;
unset($b);
echo $a, '===', $b, PHP_EOL;

下面的代码是在PHP中,咱们把$b变量指向$a,作为$a的援用变量。而后删除$b,对$a没有任何影响。

<code class="php">#include <stdio.h>
#include <stdlib.h>

int main()
{
    // C 中的指针和援用
    int a = 1;
    int* b = &a;
    printf("%i\n", a); // 1
    free(b); // free b
    printf("%i\n", a); //get error: *** error for object 0x7fff6350da08: pointer being freed was not allocated
    return 0;
}

而C中的援用指针就不行了,咱们把b变量删掉后,再打印a变量就间接报错了。

尽管说PHP的底层也是C写得,但咱们都晓得C中的指针是出了名的变态,没有肯定的功底非常容易出错。所以PHP的开发者没有裸露C的原始指针能力,而是采纳了和Java之类的相似的援用能力。这也是古代语言的个性,不须要咱们过多的关注过于底层的能力,而将更多的工夫放在业务实现上。

援用在数组和对象中的应用

如果具备援用的数组被拷贝,其值不会解除援用。对于数组传值给函数也是如此。

<code class="php">$arr1 = ["a", "b"];
$t1 = &$arr1[1];
$arr2 = $arr1;
$arr2[1] = "c";
var_dump($arr1);

// array(2) {
//     [0]=>
//     string(1) "a"
//     [1]=>
//     &string(1) "c"
// }

$arr1 = ["a", "b"];
$t1 = &$arr1[1];
unset($t1); // unset 掉援用
$arr2 = $arr1;
$arr2[1] = "c";
var_dump($arr1);

// array(2) {
//     [0]=>
//     string(1) "a"
//     [1]=>
//     string(1) "b"
// }

这个其实挺有意思的,咱们比照这两个例子能够看出一个问题,$t变量指向$arr[1]的援用。$arr2间接=这个$arr1,没有应用援用,而后$arr2批改了$arr2[1]的内容,$arr1相应的内容也产生了扭转,如果unset掉$t变量,则$arr1相应的内容就不会产生扭转。对此,我在文档中找到了上面的解释:

因为PHP外部工作的特殊性,如果对数组的单个元素进行援用,而后复制数组,无论是通过赋值还是通过函数调用中的值传递,都会将援用复制为数组的一部分。这意味着对任一数组中任何此类元素的更改都将在另一个数组(和其余援用中)中反复,即便数组具备不同的作用域(例如,一个是函数外部的参数,另一个是全局的)!在复制时没有援用的元素,以及在复制数组后调配给其余元素的援用,将失常工作(即独立于其余数组)。

不仅仅是数组,对象的援用也会有一些好玩的问题。

<code class="php">$o1 = new stdClass();
$o1->a = 'a';
var_dump($o1);
// object(stdClass)#1 (1) {
//   ["a"]=>
//   string(1) "a"
// }

$o2 = &$o1;
$o3 = $o1;

$o2->a = 'aa';

var_dump($o1);
// object(stdClass)#1 (1) {
//   ["a"]=>
//   string(2) "aa"
// }

var_dump($o3); // $o2批改了$a为'aa',$o3也变成了'aa'
// object(stdClass)#1 (1) {
//   ["a"]=>
//   string(2) "aa"
// }

$o1->a = 'aaa';
$o1 = null;
var_dump($o2); // $o2援用变成了null
// NULL

var_dump($o3); // $o3不仅援用还存在,并且$a变成了'aaa'
// object(stdClass)#1 (1) {
//   ["a"]=>
//   string(3) "aaa"
// }

下面例子中有三个对象,$o1、$o2、$o3,其中,$o2是对$o1的援用,$o3是间接赋值为$o1。对$o2属性的操作不仅会反映在$o1中,也会反映到$o3中。其实咱们之前专门有一篇文章就讲的这个问题,首先对象默认赋值就是援用,其次这个例子很好地证实了援用就是一个符号表的绑定。删除了快捷方式对原始对象和其余快捷方式没有任何影响。大家能够参考:对象赋值在PHP中到底是不是援用?

援用的传递

对于援用在办法参数上的传递,最重要的是记住两点:一是办法外部批改了变量内部也会变,这是援用的个性嘛;二是只能传递变量、New 语句、从函数中返回的援用三种类型。

<code class="php">error_reporting(E_ALL);
function foo(&$var)
{
    $var++;
    echo 'foo:', $var;
}
function bar() // Note the missing &
{
    $a = 5;
    return $a;
}
foo(bar()); // 自 PHP 5.0.5 起导致致命谬误,自 PHP 5.1.1 起导致严格模式谬误
            // 自 PHP 7.0 起导致 notice 信息,Notice: Only variables should be passed by reference
foo($a = 5); // 表达式,不是变量, Notice: Only variables should be passed by reference
// foo(5); // 导致致命谬误 !5是个常量!

///////////////////////////////
// 正确的传递类型
$a = 5;
foo($a); // 变量

function &baz()
{
    $a = 5;
    return $a;
}
foo(baz()); // 从函数中返回的援用

function foo1(&$var)
{
    print_r($var);
}
foo1(new stdClass()); // new 表达式

援用的返回

援用的返回并不是常常应用的一个能力。文档中的原文是:不要用返回援用来减少性能,引擎足够聪慧来本人进行优化。仅在有正当的技术起因时才返回援用!

<code class="php">$a = 1;
function &test(){
    global $a;
    return $a;
}

$b = &test($a);
$b = 2;
echo $a, PHP_EOL;

当你想要返回一个援用变量的时候,肯定要给办法定义和办法调用的时候都应用&符号。这个是须要留神的点。当其余中央批改本来的变量值或者返回的变量值通过批改后,都会影响到所有调用这个值的中央。所以说,援用的返回是比拟危险的,因为你不分明什么时候在什么中央这个值可能产生了批改,对于bug的排查会十分艰难。

援用的勾销

勾销援用其实就是间接unset掉变量就能够了。然而肯定要记住,PHP中的援用是指向的符号表,对原始实在的值是不起作用的,所以即便unset掉了最原始的那个变量,对其它援用赋值的变量也不会有影响!!

<code class="php">$a = 1;
$b = &$a;
$c = &$b;
$b = 2;
echo '定义援用后:', $a, '===', $b, '===', $c, PHP_EOL;

unset($b);
$b = 3;
echo '勾销$b的援用,不影响$a、$c:', $a, '===', $b, '===', $c, PHP_EOL;

$b = &$a;
unset($a);
echo '勾销$a,不影响$b、$c:', $a, '===', $b, '===', $c, PHP_EOL;

// 定义援用后:2===2===2
// 勾销$b的援用:2===3===2
// 勾销$a,不影响$c:===3===2


$a = 1;
$b = & $a;
$c = & $b; // $a, $b, $c reference the same content '1'

$a = NULL; // All variables $a, $b or $c are unset
echo '所有援用成空:', $a, '===', $b, '===', $c, PHP_EOL;

总结

这一次算是比拟彻底的把援用说了个透。对于PHP的援用只有记住了它的定义就十分好了解了,最直观的就是当成是操作系统的快捷方式就好了,并没有咱们设想中的那么难,和C的指针相比真的只是娃娃级别,多多练习多多温习天然就能很好地把握应用啦!

测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202002/source/%E5%BD%BB%E5%BA%95%E6%90%9E%E6%98%8E%E7%99%BDPHP%E7%9A%84%E4%B8%AD%E5%BC%95%E7%94%A8%E7%9A%84%E6%A6%82%E5%BF%B5.php

参考文档:
https://www.php.net/manual/zh/language.references.whatare.php
https://www.php.net/manual/zh/language.references.whatdo.php
https://www.php.net/manual/zh/language.references.arent.php
https://www.php.net/manual/zh/language.references.pass.php
https://www.php.net/manual/zh/language.references.return.php
https://www.php.net/manual/zh/language.references.unset.php
https://www.php.net/manual/zh/language.references.spot.php

===========

各自媒体平台均可搜寻【硬核项目经理】


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:彻底搞明白PHP的中引用的概念

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址