0

0

php引用(&)详解及注意事项

php中文网

php中文网

发布时间:2016-06-21 08:46:46

|

1331人浏览过

|

来源于php中文网

原创

php的引用(就是在变量函数对象对象方法 等前面加上&符号)

在PHP 中引用的意思是:不同的名字访问同一个变量内容。

与C语言中的指针是有差别的。C语言中的指针里面存储的是变量的内容,在内存中存放的地址。

1.变量的引用

PHP 的引用允许你用两个变量来指向同一个内容。

立即学习PHP免费学习笔记(深入)”;

2.函数的引用传递(传址调用

传址调用我就不多说了,下面直接给出代码:

";
echo $b; //输出101
?>

要注意的是,在这里 test(1); 的话就会出错,原因自己去想。

注意:

上面的“ test($b); ” 中的$b前面不要加 & 符号,但是在函数“call_user_func_array”中,若要引用传参,就得需要 & 符号,如下代码所示:

3.函数的引用返回

先看代码:

下面解释下:

通过这种方式 $a=test(); 得到的其实不是函数的引用返回,这跟普通的函数调用没有区别,至于原因:这是PHP的规定。

PHP规定通过$a=&test(); 方式得到的才是函数的引用返回,至于什么是引用返回呢(PHP手册上说:引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。) 这句狗屁话,害我半天没看懂。

用上面的例子来解释就是:

$a = test() 方式调用函数,只是将函数的值赋给$a而已,而$a做任何改变,都不会影响到函数中的$b,而通过 $a = &test() 方式调用函数呢,它的作用是将return $b中的$b变量的内存地址与$a变量的内存地址都指向了同一个地方,即产生了相当于这样的效果 ($a = &$b;) 所以改变$a的值也同时改变了$b的值,所以在执行了

$a = &test();
$a = 5;

以后,$b的值变为了5。

这里是为了让大家理解函数的引用返回才使用静态变量的,其实函数的引用返回多用在对象中。

另附一个PHP官方例子:

data;
	}

	public function out() {
		echo $this->data;
	}
}

$aa = new talker();
$d = &$aa->get();

$aa->out();
$d = 'How';
$aa->out();
$d = 'Are';
$aa->out();
$d = 'You';
$aa->out();

// the output is "HiHowAreYou"
?>

4.对象的引用

abc; // 这里输出ABC
echo $c->abc; // 这里输出ABC
$b->abc="DEF";
echo $c->abc; // 这里输出DEF
?>

以上代码是在PHP5中的运行效果。

在PHP5中对象的赋值是个引用的过程。上列中 $b = new a; $c = $b;  其实等效于 $b = new a; $c = &$b;,PHP5中默认就是通过引用来调用对象, 但有时你可能想建立一个对象的副本,并希望原来的对象的改变不影响到副本 。为了这样的目的,PHP5定义了一个特殊的方法,称为__clone。

自 PHP 5 起,new 自动返回引用,因此在此使用 =& 已经过时了并且会产生 E_STRICT 级别的消息。在PHP4中,对象的赋值是个拷贝过程,如:$b = new a,其中new a产生的是一个匿名的a对象实例,而此时的$b是对这个匿名对象的拷贝。同理 $c = $b,也是对$b内容的一个拷贝。所以在PHP4中,为了节省内存空间,$b = new a 一般会改成引用的模式,即 $b = &new a。

下面再来个 官方 提供的例子:

在PHP5中,你不需要额外添加什么东西就可到达“对象引用”的功能:

name = $str;
	}

	function __toString() {
		return 'my name is "' . $this->name . '" and I live in "' . __CLASS__ . '".' . " ";
	}

	function setName($str) {
		$this->name = $str;
	}
}

class MasterOne {
	protected $foo;

	function __construct($f) {
		$this->foo = $f;
	}

	function __toString() {
		return 'Master: ' . __CLASS__ . '  foo: ' . $this->foo . " ";
	}

	function setFooName($str) {
		$this->foo->setName($str);
	}
}

class MasterTwo {
	protected $foo;

	function __construct($f) {
		$this->foo = $f;
	}

	function __toString() {
		return 'Master: ' . __CLASS__ . '  foo: ' . $this->foo . " ";
	}

	function setFooName($str) {
		$this->foo->setName($str);
	}
}

$bar = new foo('bar');

print(" ");
print("Only Created $bar and printing $bar ");
print($bar);

print(" ");
print("Now $baz is referenced to $bar and printing $bar and $baz ");
$baz = &$bar;
print($bar);

print(" ");
print("Now Creating MasterOne and Two and passing $bar to both constructors");
$m1 = new MasterOne($bar);
$m2 = new MasterTwo($bar);
print($m1);
print($m2);

print(" ");
print("Now changing value of $bar and printing $bar and $baz");
$bar->setName('baz');
print($bar);
print($baz);

print(" ");
print("Now printing again MasterOne and Two");
print($m1);
print($m2);

print(" ");
print("Now changing MasterTwo's foo name and printing again MasterOne and Two");
$m2->setFooName('MasterTwo\'s Foo');
print($m1);
print($m2);

print("Also printing $bar and $baz");
print($bar);
print($baz);
?>

输出:

Only Created $bar and printing $bar my name is "bar" and I live in "foo".Now $baz is referenced to $bar and printing $bar and $baz my name is "bar" and I live in "foo".Now Creating MasterOne and Two and passing $bar to both constructors Master: MasterOne  foo: my name is "bar" and I live in "foo".Master: MasterTwo  foo: my name is "bar" and I live in "foo".Now changing value of $bar and printing $bar and $baz my name is "baz" and I live in "foo". my name is "baz" and I live in "foo".Now printing again MasterOne and Two Master: MasterOne  foo: my name is "baz" and I live in "foo".Master: MasterTwo  foo: my name is "baz" and I live in "foo".Now changing MasterTwo's foo name and printing again MasterOne and Two Master: MasterOne  foo: my name is "MasterTwo's Foo" and I live in "foo".Master: MasterTwo  foo: my name is "MasterTwo's Foo" and I live in "foo".Also printing $bar and $baz my name is "MasterTwo's Foo" and I live in "foo". my name is "MasterTwo's Foo" and I live in "foo".

上个例子解析:

$bar = new foo('bar');
$m1 = new MasterOne($bar);

实例对象$m1与$m2中的$bar是对实例$bar的引用,而非拷贝,这是PHP5中,对象引用的特点,也就是说

  1. $m1或$m2内部,任何对$bar的操作都会影响外部对象实例$bar的相关值。
  2. 外部对象实例$bar的改变也会影响$m1和$m2内部的$bar的引用相关值。

在PHP4中,要实现如上述的用一个对象实例去当着另外一个对象的属性时,其等价代码(即引用调用)类似如下:

白月生产企业订单管理系统GBK2.0  Build 080807
白月生产企业订单管理系统GBK2.0 Build 080807

请注意以下说明:1、本程序允许任何人免费使用。2、本程序采用PHP+MYSQL架构编写。并且经过ZEND加密,所以运行环境需要有ZEND引擎支持。3、需要售后服务的,请与本作者联系,联系方式见下方。4、本程序还可以与您的网站想整合,可以实现用户在线服务功能,可以让客户管理自己的信息,可以查询自己的订单状况。以及返点信息等相关客户利益的信息。这个功能可提高客户的向心度。安装方法:1、解压本系统,放在

下载
class foo{
	var $bar;
	function setBar(&$newBar) {
		$this->bar = $newBar;
	}
}

5.引用的作用

如果程序比较大,引用同一个对象的变量比较多,并且希望用完该对象后手工清除它,个人建议用 "&" 方式,然后用 $var = null 的方式清除。 其它时候还是用PHP5的默认方式吧。另外,PHP5中对于大数组的传递,建议用 "&" 方式,毕竟节省内存空间使用。

6.取消引用

当你 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。例如:

不会 unset $b,只是 $a。

7.global 引用

当用 global $var 声明一个变量时实际上建立了一个到全局变量的引用。也就是说和这样做是相同的:

这意味着,例如,unset $var 不会 unset 全局变量。

如果在一个函数内部给一个声明为 global 的变量赋于一个引用,该引用只在函数内部可见。可以通过使用 $GLOBALS 数组避免这一点。

Example  在函数内引用全局变量

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

8.$this

在一个对象的方法中,$this 永远是调用它的对象的引用。

//下面再来个小插曲

PHP中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,PHP中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的。

通俗的讲

1:如果有下面的代码

其实此时 $a与$b都是指向同一内存地址 而并不是$a与$b占用不同的内存

2:如果在上面的代码基础上再加上如下代码

由于$a与$b所指向的内存的数据要重新写一次了,此时Zend核心会自动判断,自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储PHP的引用(就是在变量或者函数、对象等前面加上&符号)是个高级话题,新手多注意,正确的理解PHP的引用很重要,对性能有较大影响,而且理解错误可能导致程序错误!

很多人误解PHP中的引用跟C当中的指针一样,事实上并非如此,而且很大差别。C语言中的指针除了在数组传递过程中不用显式申明外,其他都需要使用*进行定 义,而PHP中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,PHP中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的,比如下面的代码:

$a = array('a','c'...'n');
$b = $a;

如果程序仅执行到这里,$a和$b是相同的,但是并没有像C那样,$a和$b占用不同的内存空间,而是指向了同一块内存,这就是PHP和C的差别,并不需要写成$b=&$a才表示$b指向$a的内存,zend就已经帮你实现了引用,并且zend会非常智能的帮你去判断什么时候该这样处理,什么时候不该这样处理。

如果在后面继续写如下代码,增加一个函数,通过引用的方式传递参数,并打印输出数组大小。

function printArray(&$arr) { //引用传递
	print(count($arr));
}
printArray($a);

上面的代码中,我们通过引用把$a数组传入printArray()函数,zend引擎会认为 printArray() 可能会导致对$a的改变,此时就会自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储。这就是前面提到的“写时拷贝”概念。

如果我们把上面的代码改成下面这样:

function printArray($arr) { // 值传递
	print(count($arr));
}
printArray($a);

上面的代码直接传递$a值到printArray()中,此时并不存在引用传递,所以没有出现写时拷贝。

大家可以测试一下上面两行代码的执行效率,比如外面加入一个循环1000次,看看运行的耗时,结果会让你知道不正确使用引用会导致性能下降30%以上。

自我理解:按传值的话是与函数内的参数无关,相当于局部变量的作用,而按传址(引用)的话却与函数内的参数有关,相当于全局变量的作用。而从性能方面来说,看上面分析就够。

您可能感兴趣的文章

  • php安全编程注意事项
  • 网站空间安全注意事项
  • 在php中分别使用curl的post提交数据的方法和get获取网页数据的方法总结
  • php递归函数中使用return需注意
  • php利用array_flip实现数组键值交换去除数组重复值
  • php利用正则过滤各种标签,空格,换行符的代码
  • ThinkPHP内置模板引擎的使用方法总结
  • PHP 利用 Curl Functions 实现多线程抓取网页和下载文件



PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
2026春节习俗大全
2026春节习俗大全

本专题整合了2026春节习俗大全,阅读专题下面的文章了解更多详细内容。

68

2026.02.11

Yandex网页版官方入口使用指南_国际版与俄罗斯版访问方法解析
Yandex网页版官方入口使用指南_国际版与俄罗斯版访问方法解析

本专题全面整理了Yandex搜索引擎的官方入口信息,涵盖国际版与俄罗斯版官网访问方式、网页版直达入口及免登录使用说明,帮助用户快速、安全地进入Yandex官网,高效使用其搜索与相关服务。

200

2026.02.11

虫虫漫画网页版入口与免费阅读指南_正版漫画全集在线查看方法
虫虫漫画网页版入口与免费阅读指南_正版漫画全集在线查看方法

本专题系统整理了虫虫漫画官网及网页版最新入口,涵盖免登录观看、正版漫画全集在线阅读方式,并汇总稳定可用的访问渠道,帮助用户快速找到虫虫漫画官方页面,轻松在线阅读各类热门漫画内容。

40

2026.02.11

Docker容器化部署与DevOps实践
Docker容器化部署与DevOps实践

本专题面向后端与运维开发者,系统讲解 Docker 容器化技术在实际项目中的应用。内容涵盖 Docker 镜像构建、容器运行机制、Docker Compose 多服务编排,以及在 DevOps 流程中的持续集成与持续部署实践。通过真实场景演示,帮助开发者实现应用的快速部署、环境一致性与运维自动化。

4

2026.02.11

Rust异步编程与Tokio运行时实战
Rust异步编程与Tokio运行时实战

本专题聚焦 Rust 语言的异步编程模型,深入讲解 async/await 机制与 Tokio 运行时的核心原理。内容包括异步任务调度、Future 执行模型、并发安全、网络 IO 编程以及高并发场景下的性能优化。通过实战示例,帮助开发者使用 Rust 构建高性能、低延迟的后端服务与网络应用。

1

2026.02.11

Spring Boot企业级开发与MyBatis Plus实战
Spring Boot企业级开发与MyBatis Plus实战

本专题面向 Java 后端开发者,系统讲解如何基于 Spring Boot 与 MyBatis Plus 构建高效、规范的企业级应用。内容涵盖项目架构设计、数据访问层封装、通用 CRUD 实现、分页与条件查询、代码生成器以及常见性能优化方案。通过完整实战案例,帮助开发者提升后端开发效率,减少重复代码,快速交付稳定可维护的业务系统。

6

2026.02.11

包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法
包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法

本专题汇总了包子漫画官网和网页版入口,提供最新章节抢先看方法、正版免费阅读指南,以及稳定访问方式,帮助用户快速直达包子漫画页面,无广告畅享全集漫画内容。

159

2026.02.10

MC.JS网页版快速畅玩指南_MC.JS官网在线入口及免安装体验方法
MC.JS网页版快速畅玩指南_MC.JS官网在线入口及免安装体验方法

本专题汇总了MC.JS官网入口和网页版快速畅玩方法,提供免安装访问、不同版本(1.8.8、1.12.8)在线体验指南,以及正版网页端操作说明,帮助玩家轻松进入MC.JS世界,实现即时畅玩与高效体验。

89

2026.02.10

谷歌邮箱网页版登录与注册全指南_Gmail账号快速访问与安全操作教程
谷歌邮箱网页版登录与注册全指南_Gmail账号快速访问与安全操作教程

本专题汇总了谷歌邮箱网页版的最新登录入口和注册方法,详细提供官方账号快速访问方式、网页版操作教程及安全登录技巧,帮助用户轻松管理Gmail邮箱账户,实现高效、安全的邮箱使用体验。

78

2026.02.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
前端系列快速入门课程
前端系列快速入门课程

共4课时 | 0.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号