No, objects are not automatically passed by reference

While it makes sense for PHP beginners to first learn that objects are passed by reference rather than focus on technical details they need not comprehend yet, it worries me how many experienced developers still hold this belief.

The basic example used to justify said misconception is the following:

The function func has its sole argument passed by value, yet it somehow changed the state of $object. Is that not what passing by reference does?

Well, not exactly. Consider the following, where the object is replaced with a new one inside the function:

Here, $object remains unchanged. However, if we add a reference:

We now revert to the original behavior.

Now it has been shown that references do make a difference for objects, the best way to understand why is to clearly define both.

A reference, first, is nothing but an alias, which means that both variables point to the same location in memory and can therefore be used interchangeably.

An object variable, on the other hand, doesn’t contain the object itself but an identifier that allows the runtime to access its content. In fact, it works exactly like pointers in C++, and therefore explains PHP’s use of the same syntax as the ‘member of pointer’ operator (->), which translates to ‘point to the given property for the object of given identifier’.

What happens in the first example is that this identifier is passed by value and copied to $arg in the function scope. Then, the runtime is asked to modify the property prop of the object corresponding to the identifier. The variable $object in the global scope was never modified, but the object it points to was.

In the second example, the identifier is once again passed by value, but then, the local variable $arg is overridden with another identifier to another object, and it is the property prop of that second object that is modified, explaining why the original one remains unchanged.

The third example, finally, has the identifier passed by reference to func. A second object is once again created, and its identifier is saved in the alias $arg, which is, by definition, just another way to refer to the variable $object in the global scope, which in turn now points to a new, modified object.

Back to pointers to objects in C++, the code below shows how they can be used to obtain the exact same behavior as PHP objects:

Though, if you know how pointers work, you probably didn’t need to read this article anyway.

In C#, the behavior is once again the same, but the introduction of reference types (variables that store references to their data, as opposed to directly containing the data) abstracts the concept of pointers and allows us to use objects directly, and with the ‘member of’ operator (.) only:

Please note that C# actually supports pointers (to value types and other pointer types), though they should only be used to interact with native functions or in performance-critical code.