[php] Are arrays in PHP copied as value or as reference to new variables, and when passed to functions?

TL;DR

a) the method/function only reads the array argument => implicit (internal) reference
b) the method/function modifies the array argument => value
c) the method/function array argument is explicitly marked as a reference (with an ampersand) => explicit (user-land) reference

Or this:
- non-ampersand array param: passed by reference; the writing operations alter a new copy of the array, copy which is created on the first write;
- ampersand array param: passed by reference; the writing operations alter the original array.

Remember - PHP does a value-copy the moment you write to the non-ampersand array param. That's what copy-on-write means. I'd love to show you the C source of this behaviour, but it's scary in there. Better use xdebug_debug_zval().

Pascal MARTIN was right. Kosta Kontos was even more so.

Answer

It depends.

Long version

I think I'm writing this down for myself. I should have a blog or something...

Whenever people talk of references (or pointers, for that matter), they usually end up in a logomachy (just look at this thread!).
PHP being a venerable language, I thought I should add up to the confusion (even though this a summary of the above answers). Because, although two people can be right at the same time, you're better off just cracking their heads together into one answer.

First off, you should know that you're not a pedant if you don't answer in a black-and-white manner. Things are more complicated than "yes/no".

As you will see, the whole by-value/by-reference thing is very much related to what exactly are you doing with that array in your method/function scope: reading it or modifying it?

What does PHP says? (aka "change-wise")

The manual says this (emphasis mine):

By default, function arguments are passed by value (so that if the value of the argument within the function is changed, it does not get changed outside of the function). To allow a function to modify its arguments, they must be passed by reference.

To have an argument to a function always passed by reference, prepend an ampersand (&) to the argument name in the function definition

As far as I can tell, when big, serious, honest-to-God programmers talk about references, they usually talk about altering the value of that reference. And that's exactly what the manual talks about: hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value".

There's another case that they don't mention, though: what if I don't change anything - just read?
What if you pass an array to a method which doesn't explicitly marks a reference, and we don't change that array in the function scope? E.g.:

<?php
function readAndDoStuffWithAnArray($array) 
{
    return $array[0] + $array[1] + $array[2];
}

$x = array(1, 2, 3);

echo readAndDoStuffWithAnArray($x);

Read on, my fellow traveller.

What does PHP actually do? (aka "memory-wise")

The same big and serious programmers, when they get even more serious, they talk about "memory optimizations" in regards to references. So does PHP. Because PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting, that's why.

It wouldn't be ideal to pass HUGE arrays to various functions, and PHP to make copies of them (that's what "pass-by-value" does, after all):

<?php

// filling an array with 10000 elements of int 1
// let's say it grabs 3 mb from your RAM
$x = array_fill(0, 10000, 1); 

// pass by value, right? RIGHT?
function readArray($arr) { // <-- a new symbol (variable) gets created here
    echo count($arr); // let's just read the array
}

readArray($x);

Well now, if this actually was pass-by-value, we'd have some 3mb+ RAM gone, because there are two copies of that array, right?

Wrong. As long as we don't change the $arr variable, that's a reference, memory-wise. You just don't see it. That's why PHP mentions user-land references when talking about &$someVar, to distinguish between internal and explicit (with ampersand) ones.

Facts

So, when an array is passed as an argument to a method or function is it passed by reference?

I came up with three (yeah, three) cases:
a) the method/function only reads the array argument
b) the method/function modifies the array argument
c) the method/function array argument is explicitly marked as a reference (with an ampersand)


Firstly, let's see how much memory that array actually eats (run here):

<?php
$start_memory = memory_get_usage();
$x = array_fill(0, 10000, 1);
echo memory_get_usage() - $start_memory; // 1331840

That many bytes. Great.

a) the method/function only reads the array argument

Now let's make a function which only reads the said array as an argument and we'll see how much memory the reading logic takes:

<?php

function printUsedMemory($arr) 
{
    $start_memory = memory_get_usage();

    count($arr);       // read
    $x = $arr[0];      // read (+ minor assignment)
    $arr[0] - $arr[1]; // read

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1); // this is 1331840 bytes
printUsedMemory($x);

Wanna guess? I get 80! See for yourself. This is the part that the PHP manual omits. If the $arr param was actually passed-by-value, you'd see something similar to 1331840 bytes. It seems that $arr behaves like a reference, doesn't it? That's because it is a references - an internal one.

b) the method/function modifies the array argument

Now, let's write to that param, instead of reading from it:

<?php

function printUsedMemory($arr)
{
    $start_memory = memory_get_usage();

    $arr[0] = 1; // WRITE!

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1);
printUsedMemory($x);

Again, see for yourself, but, for me, that's pretty close to being 1331840. So in this case, the array is actually being copied to $arr.

c) the method/function array argument is explicitly marked as a reference (with an ampersand)

Now let's see how much memory a write operation to an explicit reference takes (run here) - note the ampersand in the function signature:

<?php

function printUsedMemory(&$arr) // <----- explicit, user-land, pass-by-reference
{
    $start_memory = memory_get_usage();

    $arr[0] = 1; // WRITE!

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1);
printUsedMemory($x);

My bet is that you get 200 max! So this eats approximately as much memory as reading from a non-ampersand param.

Examples related to php

I am receiving warning in Facebook Application using PHP SDK Pass PDO prepared statement to variables Parse error: syntax error, unexpected [ Preg_match backtrack error Removing "http://" from a string How do I hide the PHP explode delimiter from submitted form results? Problems with installation of Google App Engine SDK for php in OS X Laravel 4 with Sentry 2 add user to a group on Registration php & mysql query not echoing in html with tags? How do I show a message in the foreach loop?

Examples related to arrays

PHP array value passes to next row Use NSInteger as array index How do I show a message in the foreach loop? Objects are not valid as a React child. If you meant to render a collection of children, use an array instead Iterating over arrays in Python 3 Best way to "push" into C# array Sort Array of object by object field in Angular 6 Checking for duplicate strings in JavaScript array what does numpy ndarray shape do? How to round a numpy array?

Examples related to reference

Method Call Chaining; returning a pointer vs a reference? When to create variables (memory management) Reference to non-static member function must be called Cannot find reference 'xxx' in __init__.py - Python / Pycharm c++ "Incomplete type not allowed" error accessing class reference information (Circular dependency with forward declaration) C++ initial value of reference to non-const must be an lvalue Dependent DLL is not getting copied to the build output folder in Visual Studio How to write to error log file in PHP How to reference Microsoft.Office.Interop.Excel dll? Linker Error C++ "undefined reference "

Examples related to pass-by-reference

Passing an integer by reference in Python Does JavaScript pass by reference? Object passed as parameter to another class, by value or reference? change values in array when doing foreach Call-time pass-by-reference has been removed C++ pass an array by reference Passing Objects By Reference or Value in C# Pass variables by reference in JavaScript JavaScript by reference vs. by value How to do the equivalent of pass by reference for primitives in Java

Examples related to pass-by-value

Passing an integer by reference in Python Does JavaScript pass by reference? Passing Objects By Reference or Value in C# JavaScript by reference vs. by value How to pass objects to functions in C++? Are arrays in PHP copied as value or as reference to new variables, and when passed to functions? Is JavaScript a pass-by-reference or pass-by-value language? Why should I use the keyword "final" on a method parameter in Java? Pass by Reference / Value in C++ What's the difference between passing by reference vs. passing by value?