Objects are references. That mean if you assign an object to a variable and then assign this variable to another variable, the 2 variables will share the same reference to the created object.
Look at this code :
We can see, in this example, when we modify $object2, it also modify $object1.
Here is a small animation that show how the memory allocation works :
Now you can say, "Yes this is like a pointer", where I would answer "Not really". The difference reside in the fact that the references are ref counted, that mean each time an object is referenced, in a variable or in an attribute of an object, the ref count is incremented. The object in memory is destroyed when the ref count reach 0. No reference to this object exist anymore so there is no reason to keep it in memory.
When you are using pointers, there is no such thing as a ref counting, that mean if the variable you are trying to point doesn't exist anymore, the pointer will return Null.
Someone, in the World Tour 2019 in Switzerland, asked "What happens if I have a pointer to an object? Is this object ref counted?". The short answer is "No".
But let's look at an example :
Here in the first method, we create a new object that we assign to the variable $ob1. We then pass this reference to the method zz_test2. In zz_test2 we get the reference to the object assigned to $ob1. We assign it to a local variable also named $obj1. We then create 2 new objects that we assign to $ob2 and $ob3. We then assign those 2 variable to 2 new attribute of $ob1. First we create an attribute ob2 and assign a pointer to $ob2 and then we create another attribute ob3 and assign it a reference to the object assigned to $ob3.
Let's stay in the zz_test2 method and look at the ref count state at this point of the code :
Object_1 : ref count = 2 --> $ob1 in zz_test and $ob1 in zz_test2
Object_2 : ref count = 1 --> $ob2 in zz_test2
Object_3 : ref count = 2 --> $ob3 in zz_test2 and (Object 1).ob3
When we will leave the zz_test2 method, the ref count state will be :
Object_1 : ref count = 1 --> $ob1 in zz_test
Object_2 : ref count = 0
Object_3 : ref count = 1 --> (Object 1).ob3
Object_2 will be destroy when Object_1 and Object_3 will still be referenced and therefore keep in memory. So what will be the state of $ob1.ob2 ? It will point to a local variable of another method that doesn't exist anymore and will return Null.
Again a small animation that show how the memory allocation works :