A rare, yet fundamental, problem when implementing libraries for deep cloning and object graph analysis, for instance, is the reasoning about references. In the past, code that needs to detect references or reference equality had to use brittle and slow workarounds.

To remedy this situation, the ReflectionReference class was introduced as a first-class API for the reflection of references.

A function or method can either accept an argument by reference or by value. The way in which an argument is accepted is declared in the signature. It is impossible to determine in the body of a function or method whether an argument was originally a reference or not. Access to the structure, for instance an array or an object, that originally contained the value is required for this determination.

ReflectionReference requires the array and the index of the array’s value in question to be able to determine whether or not that value holds a reference. This is why ReflectionReference objects are created like so:

$array = [0];

var_dump(ReflectionReference::fromArrayElement($array, 0));

$a = &$array[0];

var_dump(ReflectionReference::fromArrayElement($array, 0)->getId());

Executing the code shown above will print the output shown below:

string(20) "..."

ReflectionReference::fromArrayElement() returns a ReflectionReference object if the specified array element holds a reference. If this element does not hold a reference then null is returned instead of a ReflectionReference object.

The ReflectionReference::getId() method returns a string that uniquely identifies the reference. This string is binary-encoded and contains unprintable characters. This is why we truncated it to ... in the output shown above.

If you want to use ReflectionReference to check whether a property of an object holds a reference then you need to cast that object to an array first:

$object = new stdClass;

$object->foo = 'bar';
$reference   = &$object->foo;
$array       = (array) $object;

var_dump(ReflectionReference::fromArrayElement($array, 'foo')->getId());

This will result in:

string(20) "..."

Again, we had to truncate the output, as you can tell by looking at the string length.