Get up to 80 % extra points for free! More info:

Lesson 6 - Reference and primitive data types in PHP

In previous lesson, Making an object-oriented component in PHP - Image Gallery, we created our very first object-oriented component – an image gallery. We have already worked with objects, aka reference data types, which act differently in some ways than so-called primitive types. It is important for you to know the inner workings of your programs so that you don't run into any unpleasant surprises.

Primitive data types

Prior to this course, we only used variables of primitive data types, i.e. numbers and arrays. In other programming languages, primitive types are attributed to simple structures as their name suggests. However, in PHP, arrays and strings are also considered primitive. As a matter of fact, all data types are considered primitive, except for objects.

Value copying

If we pass a primitive type somewhere, its value will always be copied. You may already understand this concept, but we'll try it out anyway as a review of sorts. We will create a script and create a new array, containing a single value of 56:

$a = array(56);

Then, we'll assign array $a to array $b:

$b = $a;

After which we will add a new item to array $b:

$b[] = 28;

Last of all, we print both of the arrays:

print_r($a);
print_r($b);

You probably already know what to expect:

Your page
localhost

Although we changed the contents of variable $b, its original value is still copied in variable $a. As a result, we have 2 different arrays. One with the original value, and another with the original value + the new one.

Reference data types

Reference data types, aka objects, are treated differently when being passed. Let's re-create a scenario similar to the one we just did, but this time with objects.

A Human instance should do the trick. Now let's create a referrential variable named $a and assign a Human instance to it:

require_once('classes/Human.php');
$a = new Human('Carl', 'Smith', 30);

Again, we assign $a to variable $b:

$b = $a;

Then, we change an attribute's value in variable $b (in this case, the age):

$b->age = 50;

Last of all, we print out both variables:

print_r($a);
print_r($b);
class Human
{

    public $firstName;
    public $lastName;
    public $age;
    private $fatigue = 0;

    public function __construct($firstName, $lastName, $age)
    {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
        $this->age = $age;
    }

    public function sleep($time)
    {
        $this->fatigue -= $time * 10;
        if ($this->fatigue < 0)
            $this->fatigue = 0;
    }

    public function run($distance)
    {
        if ($this->fatigue + $distance <= 20)
            $this->fatigue += $distance;
        else
            echo("I'm too tired.");
    }

    public function greet()
    {
        echo('Hi, my name is ' . $this->firstName);
    }

    public function __toString()
    {
        return $this->firstName;
    }

}

Oh, not quite the same as with primitive types, is it?

Your page
localhost

Summary

We created a Human instance, which we stored into variable $a. An instance and a variable are two completely different things. This is why instances are not to be stored directly in a variable.

Object instances are stored in a memory known as the heap. This heap is of unlimited size (its size depends on how much RAM you have). You could imagine it as a huge heap of objects. All there is in variable $a, is what is known as a reference. In other words, a value that points to the instance on the heap.

When we assigned variable $a to variable $b, we made it literally point to the same instance as $a. I've illustrated the whole thing for you, to make it a bit clearer:

Heap in PHP - Object-Oriented Programming in PHP

Here, you see a heap of objects and variables that contain references to the objects. Both variables $a and $b point to the same object. For that reason, the content of variable $a was changed when we changed $b. There is only one human in this scenario, which was not the case in the primitive type example.

Working with references is a natural and fast process. We would only need to create an object once, and then pass it by reference anywhere it is needed. If you wanted to use an array in PHP at multiple places, its contents could easily be copied, which may be a bad thing when working with large sums of data. Passing a huge object is an inexpensive operation if all that is passed is a reference to it. Eventually, you will see just how natural and simple of a process it is to use references. Keep in mind, that in most cases, things simply cannot be copied.

Note: Most programming languages work in a referential manner when it comes to arrays and strings as well. Mainly because primitive types are stored in a memory called the stack. The stack is very fast, but its size is very limited. Complex data types (usually of unlimited length) are stored on the heap and have a reference that points to them added to the heap. PHP is internally cheating on the way things usually work because it simulates treating arrays as primitive data types, even though it physically stores them on the heap.

Forcing references

As I've mentioned before, PHP works with everything except objects as primitive data types. Meaning that a value is always copied when passing variables. This can be useful at times, but sometimes it may be inconvenient. For this reason, we are able to pass a variable of a primitive type (e.g. an array) by references. Just to be clear, I highly recommend that you avoid using these hacks, as it alters the principle of how PHP works by default. If you forget exactly what you did, you may end up with lots of unpleasant surprises. The only reason I tell you about these crooked tricks is for completeness' sake.

Passing variables by parameter

Imagine that you have a function that adds something that you pass through its parameter into an array. Here's the wrong way to do it:

// This code does not work
function add($array, $item)
{
    $array[] = $item;
}

The code above won't add anything into the array:

$a = array(1, 2, 3);
add($a, 4);
print_r($a);

This is because array $a is copied into the $array variable and a new item is added into this entirely new array. The original array will not change at all. We can, however, force the function to pass the parameter via reference (as if it were an object) using the "&" operator:

function add(&$array, $item)
{
    $array[] = $item;
}

The code will work now, however, it is more of a hack and could go wrong in so many ways. If we wrote code in an object-oriented way, as you can see add() was declared as a function, not a method, we wouldn't even need to do any of this. The array would be an object property, which would make modifying it trivial. In fact, we would have one less attribute:

public function add($item)
{
    $this->array[] = $item;
}

As you can see, objects make things much simpler and protect you from unclear code. The correct non-object-oriented solution would be to return the modified array and then assign it back to the $a variable. Either way, the entire array would be copied twice, which is not very efficient.

Modifying arrays in a loop

Forcing references can come in handy when iterating over an array using a foreach loop where we needed to change its values. The following code won't work:

// This code won't work
$a = array(1, 2, 3);
foreach ($a as $item)
{
    $item++;
}
print_r($a);

The array item will be copied (unless it's an object) into the $item variable which we altered. Meaning that we are not able to access the original item. Here is what it would look like with forced references implemented:

$a = array(1, 2, 3);
foreach ($a as &$item)
{
    $item++;
}
print_r($a);

Now, $item points to the original array item. Meaning that not only the copied item, but the original array is modified as well. This way is less confusing than forcing references using functions. Regardless, the same result can be achieved using a for loop or using built-in functions, that PHP offers for working with arrays.

In the next lesson, Solved tasks for OOP in PHP lessons 4-6, we will introduce you all to inheritance and polymorphism, which along with encapsulation make up the pillars on which OOP stands.

In the following exercise, Solved tasks for OOP in PHP lessons 4-6, we're gonna practice our knowledge from previous lessons.


 

Previous article
Making an object-oriented component in PHP - Image Gallery
All articles in this section
Object-Oriented Programming in PHP
Skip article
(not recommended)
Solved tasks for OOP in PHP lessons 4-6
Article has been written for you by David Capka Hartinger
Avatar
User rating:
1 votes
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn university David learned IT at the Unicorn University - a prestigious college providing education on IT and economics.
Activities