Babiker
Babiker

Reputation: 18798

Using references in PHP

I ask this question because i learned that in programming and designing, you must have a good reason for decisions. I am php learner and i am at a crossroad here, i am using simple incrementation to try to get what im asking across. I am certainly not here to start a debate about the pros/cons of referencing, but when it comes to php, which is the better programming practice:

function increment(&$param) {
      ++$param;
}

vs.

function increment($param){
 return ++$param;
}

$param = increment($param);

Upvotes: 4

Views: 1401

Answers (8)

John M.
John M.

Reputation: 2264

I just ran a couple quick tests with the following code:

<?php

function increment(&$param){
 $param++;
}
$param = 1;

$start = microtime();

for($i = 1; $i <= 1000000; $i++) {
    increment($param);
}

$end = microtime();

echo $end - $start;

?>

This returned, consistently around .42 to .43, where as the following code returned about .55 to .59

<?php

function increment($param){
 return $param++;
}
$param = 1;

$start = microtime();

for($i = 1; $i <= 1000000; $i++) {
    $param = increment($param);
}

$end = microtime();

echo $end - $start;

?>

So I would say that the references are quicker, but only in extreme cases.

Upvotes: 1

deceze
deceze

Reputation: 522016

It depends on what the functions purpose is. If its express purpose is to modify the input, use references. If the purpose is to compute some data based on the input and not to alter the input, by all means use a regular return.

Take for example array_push:

int array_push(array &$array, mixed $var[, mixed $...])

The express purpose of this function is to modify an array. It's unlikely that you need both the original array and a copy of it including the pushed values.

array_push($array, 42); // most likely use case

// if you really need both versions, just do:
$old = $array;
array_push($array, 42);

If array_push didn't take references, you'd need to do this:

// array_push($array, $var[, $...])
$array = array_push($array, 42); // quite a waste to do this every time

On the other hand, a purely computational function like pow should not modify the original value:

number pow(number $base, number $exp)

You are probably more likely to use this function in a context where you want to keep the original number intact and just compute a result based on it. In this case it would be a nuisance if pow modified the original number.

$x = 123;
$y = pow($x, 42); // most likely use case

If pow took references, you'd need to do this:

// pow(&$base, $exp)
$x = 123;
$y = $x; // nuisance
pow($y, 42);

Upvotes: 3

Bill Karwin
Bill Karwin

Reputation: 562260

First, references are not pointers.

I tried the code given by @John in his answer, but I got strange results. It turns out microtime() returns a string. Arithmetic is unreliable and I even got negative results on some runs. One should use microtime(true) to get the value as a float.

I added another test of no function call, just incrementing the variable:

<?php

$param = 1;

$start = microtime(true);

for($i = 1; $i <= 1000000; $i++) {
    $param++;
}

$end = microtime(true);

echo "increment: " . ($end - $start) . "\n";

The results on my machine, Macbook 2.4GHz running PHP 5.3.2.

  • function call with pass by reference: 2.14 sec.
  • function call with pass by value: 2.26 sec.
  • no function call, just bare increment: 0.42 sec.

So there seems to be a 5.3% performance advantage to passing by reference, but there is a 81% performance advantage to avoiding the function call completely.

I guess the example of incrementing an integer is arbitrary, and the OP is really asking about the general advantage of passing by reference. But I'm just offering this example to demonstrate that the function call alone incurs far more overhead than the method of passing parameters.

So if you're trying to decide how to micro-optimize parameter passing, you're being penny wise and pound foolish.

There are also other reasons why you should avoid references. Though they can simplify several algorithms, especially when you are manipulating two or more data structures that must have the same underlying data:

  • They make functions have side-effects. You should, in general, avoid functions with side-effects, as they make the program more unpredictable (as in "OK, how this did this value get here? did any of the functions modify its parameters?")
  • They cause bugs. If you make a variable a reference, you must remember to unset it before assigning it a value, unless you want to change the underlying value of the reference set. This happens frequently after you run a foreach loop by reference and then re-use the loop variable.

Upvotes: 10

Justin Frankel
Justin Frankel

Reputation: 117

The second version:

function increment($param){
 return $param++;
}

$param = increment($param);

Does nothing. increment() returns $param. Perhaps you meant ++$param or $param+1;

I mention this not to be pedantic, but so that if you compare timings, you are comparing the same function (it could be possible for PHP's optimizer to remove the function completely).

Upvotes: 2

jlindenbaum
jlindenbaum

Reputation: 1881

I'd say it would quite depend on what you're doing. If you're trying to interact on a large set of data without wanting an extra copy of it in memory - go ahead, pass by value (your second example). If you want to save the memory, and interact on an object directly - pass by reference (your first example)

Upvotes: 0

Entendu
Entendu

Reputation: 1245

The best practice is not to write a function when an expression will do.

$param++;

is all you need.

Upvotes: 2

Matt Mitchell
Matt Mitchell

Reputation: 41823

I think your example is a little abstract.

There is no problem with using pointers but in most real-world cases you are probably modifying an object not an int in which case you don't need the reference (in PHP5 at least).

Upvotes: 0

BoltClock
BoltClock

Reputation: 723448

By definition, incrementing a variable's value (at least in PHP) mutates the variable. It doesn't take a value, increase it by 1 and return it; rather it changes the variable holding that value.

So your first example would be the better way to go, as it's taking a reference (PHP doesn't really do pointers per se) of $param and post-incrementing it.

Upvotes: 1

Related Questions