← PHP按值传递:理解函数参数的默认传递机制 PHP函数默认参数:给参数设定备选值,提升调用灵活性 →

PHP按引用传递:让函数直接修改外部变量的机制

原创 2026-05-09 PHP 已有人查阅

上一节我们讲了按值传递,它的核心是“函数拿副本,原值不受影响”。这是一种安全的隔离机制。但有些场景下,你恰恰需要函数去修改外部原始变量——比如交换两个变量的值、给数组批量加前缀、或者一次性从函数返回多个计算结果。这时候,按引用传递(Call by Reference) 就该上场了。

按引用传递的核心规则:函数接收的不是变量值的副本,而是变量本身在内存中的地址。 函数内部对这个参数的任何修改,直接作用于外部的原始变量。这个机制打破了函数内外的数据隔离,赋予了函数直接操控外部变量的能力。

语法与基础示例

让一个参数变成按引用传递很简单:在函数定义时,给参数名前面加一个&符号。

function 函数名(&$参数名) {
    // 对$参数名的修改会直接影响外部原始变量
}

调用时语法和普通函数一样,不需要额外加任何符号。&只出现在定义里。

基础示例:字符串追加

<?php
function appendText(&$str) {
    $str .= "——追加的文本内容";
}

$myText = "原始内容";
appendText($myText);
echo $myText;
?>

输出:原始内容——追加的文本内容

$myText在调用appendText()之后实实在在地变了。因为&$str拿到的是$myText的引用,函数内部的.=拼接操作直接作用在原始变量上。这和按值传递形成鲜明对比——如果去掉那个&$myText依然是"原始内容",函数内部的修改只影响副本。

多个实例深入理解

实例1:数值递增

<?php
function increase(&$num) {
    $num++;
}

$count = 10;
increase($count);
echo "递增后的值:{$count}";
?>

输出:递增后的值:11

按值传递需要把递增后的值return出来再重新赋值。按引用传递省掉了这一步,$count直接被函数内部操作改了。

实例2:交换两个变量的值

这是一个很能体现按引用传递优势的经典场景。没有引用的话,交换函数无法工作。

<?php
function swapValues(&$a, &$b) {
    $temp = $a;
    $a = $b;
    $b = $temp;
}

$x = 5;
$y = 10;
echo "交换前:x = {$x},y = {$y}<br/>";

swapValues($x, $y);
echo "交换后:x = {$x},y = {$y}";
?>

输出:

交换前:x = 5,y = 10
交换后:x = 10,y = 5

函数需要同时修改两个外部变量。只有按引用传递能做到这一点——函数直接操作$x$y的内存地址,把它们的值互换。

实例3:批量修改数组元素

处理数组时,按引用传递能让你把数组传给函数,函数直接在原数组上做修改,而不是返回一个新数组。

<?php
function addPrefix(&$arr, $prefix) {
    // 注意:这里$value前面也要加&,否则只改副本
    foreach ($arr as &$value) {
        $value = $prefix . $value;
    }
}

$fruitList = ['苹果', '香蕉', '樱桃'];
addPrefix($fruitList, '新鲜');
print_r($fruitList);
?>

输出:

Array
(
    [0] => 新鲜苹果
    [1] => 新鲜香蕉
    [2] => 新鲜樱桃
)

这里有两个&需要注意:一个是函数参数定义时的&$arr,让函数拿到数组本身的引用;另一个是foreach里的&$value,让循环体内部能直接修改数组的每个元素。两个缺一不可。

实例4:函数返回引用

按引用的思路不仅能用“进”的方向(传参),还能用到“出”的方向(返回值)。一个函数可以返回对某个变量的引用,调用方拿到引用后可以直接修改原始数据。

<?php
// 注意函数名前也有&,表示这个函数返回的是引用
function &getElement(&$arr, $key) {
    return $arr[$key];
}

$userData = ['name' => 'Alice', 'age' => 25];

// 用=&接收引用,而不是复制值
$nameRef =& getElement($userData, 'name');
$nameRef = 'Bob';

echo $userData['name']; // 输出Bob,原始数组被修改了
?>

输出:Bob

getElement()返回的不是$userData['name']的值"Alice",而是这个元素本身的内存引用。$nameRef =&拿到这个引用后,给$nameRef赋新值,等于直接修改了$userData数组里的对应元素。

本节课程知识要点

按引用传递是一个有权限的工具,使用时有几个关键点需要把握:

  • &写在函数定义里,调用时不加。这点容易搞混。定义时function foo(&$param),调用时就是foo($var),不会写成foo(&$var)

  • 按引用传递绕过了作用域隔离。函数可以直接修改外部变量,这是一种能力,也是一份责任。用得好很便捷,用过头会让数据流变得难以追踪。

  • 不是所有变量都能按引用传递。比如你不能把一个字面量(如foo(&5))传给引用参数,5没有内存地址。只能传变量。

  • foreach里修改数组元素也要加&。这是另一个常见的&使用场景,和函数参数引用是同一个原理。

  • 取消引用用unset()。如果foreach里用了&$value,循环结束后记得unset($value),否则后续对$value的误操作可能会意外修改数组的之后一个元素。

按引用传递的实用价值

1. 优化大数据的处理性能

按值传递在遇到大型数组或对象时,会复制整个数据结构,消耗内存和时间。按引用传递只传一个内存地址,避免了复制开销。

<?php
function processLargeData(&$data) {
    // 直接在原数据上操作,无需复制
    $data['processed'] = true;
}

$largeArray = range(1, 100000); // 十万个元素的数组
processLargeData($largeArray);
?>

$largeArray有十万个元素,如果按值传递,PHP要在内存里再复制十万个元素。按引用传递只传一个指针,这在处理大量数据时有可见的性能差异。

2. 支持链式调用

在面向对象编程里,方法返回$this的引用,可以实现链式调用,让代码更紧凑。

<?php
class Counter {
    private $count = 0;

    public function &inc() {
        $this->count++;
        return $this;
    }

    public function getCount() {
        return $this->count;
    }
}

$counter = new Counter();
// 链式调用:连续三次递增
$counter->inc()->inc()->inc();
echo "计数结果:" . $counter->getCount();
?>

输出:计数结果:3

inc()返回$this的引用,所以可以紧接着继续调用inc(),一行代码完成多次递增。

3. 从函数返回多个值

PHP函数本身只能return一个值。如果想返回多个计算结果,一种方案是把用于接收结果的变量以引用方式传入函数,让函数把结果“写”进这些变量。

<?php
function calculate($a, $b, &$sum, &$product) {
    $sum = $a + $b;
    $product = $a * $b;
}

$num1 = 4;
$num2 = 5;
calculate($num1, $num2, $total, $multiplyResult);

echo "和:{$total},积:{$multiplyResult}";
?>

输出:和:9,积:20

$total$multiplyResult在调用前是未初始化的,函数内部通过引用直接给它们赋了值。调用结束后,外部就有了两个计算结果。

什么时候用按引用传递,什么时候不用

主观建议: 在代码号学习编程的过程中,按引用传递是一个功能比较强的工具,但用之前值得想一想。如果按值传递配合return就能解决问题,我倾向于用那种方式——数据流是单向的,容易追踪。在以下几种情况下,按引用传递是更自然的选择:

  • 需要函数直接修改传入的数组或大对象,而且调用方的意图就是“把这个数据交给函数处理,处理完它就得变”。

  • 需要一次调用返回多个值,且用数组封装返回值会让调用方代码变丑。

  • 操作大型数据集为了性能考虑,避免不必要的复制。

如果不属于以上场景,按值传递是更稳妥的默认选项。按引用传递打破了函数内外的边界,边界一旦模糊,调试时就要多留一个心眼。

按引用传递和按值传递不是对立的,而是互补的。理解了两者的区别和适用场景,你就能在写函数时做出有依据的取舍——什么时候让函数安分守己地只依赖参数和返回值,什么时候给它直接操作外部变量的权限。这个判断力的形成,需要时间的积累。但方向对了,积累起来就快。

← PHP按值传递:理解函数参数的默认传递机制 PHP函数默认参数:给参数设定备选值,提升调用灵活性 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号