Passing by Reference in PHP

Table of contents

An often-overlooked feature of the PHP programming language are references. While they may seem similar to pointers in other languages, they are not quite the same. Understanding how references work and how to use them effectively can ease development of complex code, while assuming they are equivalent to pointers may result in wrong assumptions about performance benefits.

Using references

A reference in PHP is a variable that acts like a proxy for another variable, so that changes to the value from one variable will be reflected by the other:

$a = 4;
$b = &$a;
$b = 2;
echo $a; // 2

Here we created two variables, $a with value 4, and $b as a reference to $a by using the & operator in front of it during assignment. Since $a and $b now point to the same variable, changing the value of $b will also change the value of $a, and vice-versa.

This is commonly used to pass variables by reference to functions, which allows the function to modify the original variable:

function double(int &$n){
  $n *= 2;
}
$a = 2;
double($a);
print($a); // 4

A function can mark any parameter as pass by reference, which will automatically pass a reference of the original variable when calling the function, without any special requirements on the caller. This gives the function double() access to the original variable $a, referenced by $n within the function body. By changing the value of $n within the function, the value of $a outside of the function is also changed. There are many built-in functions like array_push(), that provide examples for real-world use cases of passing by reference.

Returning references

Another use of references is when returning variables from a function. This is the inverse version of passing by reference, allowing a function to return a reference to a variable instead a value. To use this feature, both the function name and the function call need to be prefixed with the & operator:

class Car{
   var int $fuel = 101;
   public function &get_fuel(){
      return $this->fuel;
   }
}

$myCar = new Car();
$fuel = &$myCar->get_fuel();
$fuel = 99;
print($myCar->fuel); // 99

Here the function get_fuel() is prefixed with the & operator, marking it's return value as a reference rather than a value. The assignment of $fuel calling the function also prefixes it with the & operator, to signal that it is assigning a reference to $fuel, rather than the value of the returned reference. Even if a function is defined as returning a reference, if the & operator is not prepended to the function call, it will still be treated as a return value instead of a reference.

References are not pointers

For developers familiar with other (especially compiled) programming languages, references may look a lot like pointers at first glance. While the referencing behaviour is the same as a pointer's, using return by reference for performance gains is ill-advised, as even the documentation advises against it:

Do not use return-by-reference to increase performance. The engine will automatically optimize this on its own.

For passing by reference, the case is a little less clear: Since the Zend engine uses copy-on-write, using references for small function parameters can actually be slower than passing by value (unless you modify them within the function). With increasing value size, passing by reference becomes more efficient. Take this with a grain of salt, because the gain in performance even for a 100k character string is about 3%, an almost negligible amount of speed for most code at the cost of increased complexity.

More articles

Setting up the Kubernetes Dashboard

Deploying a visual overview of your k8s cluster

Upgrading a PostgreSQL Database with Docker

Safely switching between major releases

A practical guide to filesystems

Picking the best option to format your next drive

A primer on LVM

Making the most of your storage devices

Automated security hardening on RockyLinux with OpenSCAP

Securing enterprise linux in less than a minute