Objects and references in memory in PHP

Today we will talk about how PHP creates objects in memory when performing a statement like $a= new Foo(); and how the references are managed in memory, since this is an issue that can generate discussion and difference of opinions. For that, we are going to talk about what references are NOT in PHP. Finally, we will talk about how the garbage collector works in PHP.

Objects and references in PHP

A statement that is widespread in PHP books, and online in general, is that in PHP objects, by default, are passed by reference. Still others say that objects in PHP are allocated by copy. These statements are not entirely certain, and to confirm it, first we have to analyze what is (and what are NOT) references in PHP.

What are not references in PHP?

I think that more important than knowing what are references in PHP it is what are NOT references in PHP. In PHP references are not C-style pointers, we can not do arithmetic with references as you can do in C. Why? Because PHP references are not really memory addresses as in C, are not numbers indicating a memory location. But… what are actually references?

What are references in PHP?

In PHP, references are “aliases” that allow two different variables to write on the same value. Or put it another way, they are a mechanism that allows accessing the same value from variables with different names and behave as if they were the same variable. Keep in mind that in PHP variable name and the contents of that variable are two totally different things that are linked in what it is called the symbols table. So when we create a reference, it is simply adding an alias for that variable in the symbol table of PHP. Let us see an example, suppose we have the following code:

$a = new Foo();

When the above statement is executed, what is actually happening is that it creates a variable “a” in memory, an object of type Foo is created in memory and an entry is added to the PHP’s symbol table which indicates that the variable $a “references” (or is related to, or “points” to, or whatever you want to call it) to Foo object, but it is NOT a pointer to that object. If you then execute the command:

$b = $a;

What is happening here it is not the case that $b becomes a reference of $a, neither can we say that $b is a copy of $a. What has really happened is that it has created a new variable “b” in memory and then added a new entry in the symbols table indicating that the variable $b, also “references” to the same Foo object than $a does. If you then execute the command:

$c = &$a;

What happens here is that it will have created a third variable “c” in memory, but NOT a new entry in the symbols table for “c” is added, instead, in the symbols table it is indicated that “c” is an alias for “a”, so it will behave identically to this, but “c” is not a pointer to “a” (which in C is known as pointers to pointers).
Consider a more complete example:

<?php

class myClass {
    public $var;
		
    function __construct() {
	$this->var = 1;
    }

    function inc() { return ++$this->var; }
}

$a = new myClass(); // $a "references" to a Foo object
$b = $a; //b also references to the same Foo object than a
//($a) == ($b) == <id> of Foo object, but a and b are different entries in symbols table

echo "$a = ";var_dump($a);
echo "$b = ";var_dump($b);

$c = &$a; //$c is an alias of $a
//($a, $c) == <id> of Foo object, c is an alias of a in the symbols table
echo "$c = ";var_dump($c);

$a = NULL;
//The entry in the symbols table which links "$a" with Foo object is removed
//Since that entry was removed, $c is not related with Foo anymore
//Anyway, Foo still exists in memory and it is still linked by $b
echo "$a = ";var_dump($a);
echo "$b = ";var_dump($b);
echo "$c = ";var_dump($c);
echo "$b->var: ".$b->inc();
echo "$b->var: ".$b->inc();

$b = NULL;
//The entry in the symbols table which links "$b" with Foo object is removed
//There are not more entries in the symbols table linked to Foo,
//So, Foo is not referenced anymore and can be deleted by garbage collector

echo "$b = ";var_dump($b);

The outputs produced by the implementation of the script above are:

$a = object(myClass)#1 (1) { ["var"]=> int(1) } 
$b = object(myClass)#1 (1) { ["var"]=> int(1) } 

$c = object(myClass)#1 (1) { ["var"]=> int(1) } 
$a = NULL 
$b = object(myClass)#1 (1) { ["var"]=> int(1) } 
$c = NULL 
$b->var: 2
$b->var: 3

$b = NULL

Garbage collector

Finally, let’s see how the garbage collector works in PHP. An object or a variable in PHP memory may be removed by the garbage collector when there is no reference to that object in the symbol table. That is, PHP maintains a references counter of an object from the time it is created, so that during the execution of the script PHP increments and decrements that references counter based on the variables that are “pointing” to it. Once the references counts reaches 0 (i.e:, no one is related to that object and therefore, it is not being used), PHP marks that object as trash or removable, so that in the next pass of the garbage collector, it will remove the object from memory and that memory will be usable by PHP again.

So, we hope we have clarified a little more how PHP handles objects and variables in memory and how it “selects” the objects that should be removed by the garbage collector in PHP.

Leave a Reply

Your email address will not be published. Required fields are marked *