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

Lesson 3 - Attributes and magic methods in PHP

In the previous lesson, First object-oriented application in PHP, we went over how OOP works and created a very rudimentary object-oriented application. Today, we will continue working on the aforementioned application.

Attributes

All our Human class has at the moment is a single method. Let's add some attributes to it! Each human will have a first and last name, and an age. Here's what our class' attributes will look like:

<?php

class Human
{

    public $firstName;
    public $lastName;
    public $age;

    . . .

As you already know, attributes work just like variables, but belong to an object. The "public" keyword before each attribute makes it visible from the outside (as it did with methods).

Let's modify our greet() method and make it a bit more interesting. We want instances to say "Hi, I am" and then append the $firstName attribute's value whenever greet() is called. In other words, we're going to access an instance attribute from within the method. Something to think about is, how would we go about accessing an instance from inside a method? A class is NOT an object, it is a pattern used to create objects of a specific data type (in this case humans). The solution is pretty simple, we use the $this keyword from inside the class. This variable contains the instance with which we are currently working. The greet() method should now look like the following:

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

Now let's get back to index.php, where we created an instance last time. Go ahead and set-up the attributes that we just now added to Human class:

$carl = new Human();
$carl->firstName = 'Carl';
$carl->lastName = 'Smith';
$carl->age = 30;
$carl->greet();

Add an HTML head to the index.php to make our application render a proper website as a result. Now, when you run it, you will see that method successfully accesses the attribute and prints its value.

Your page
localhost

To test that class is universal, we'll create another instance and name it John. Here's the index.php code in its entirety (including the HTML part):

<!DOCTYPE html>

<html lang="en">
    <head>
            <meta charset="utf-8" />
            <title>ICT.social PHP course - OOP</title>
    </head>

    <body>
        <?php
        require_once('classes/Human.php');

        $carl = new Human();
        $carl->firstName = 'Carl';
        $carl->lastName = 'Smith';
        $carl->age = 30;

        $john = new Human();
        $john->firstName = 'John';
        $john->lastName = 'Newman';
        $john->age = 24;

        $carl->greet();
        echo('<br />');
        $john->greet();

        ?>
    </body>
</html>

Application output:

Your page
localhost

Objects are highly universal components. Once you create a class, you can work with any number of unique instances. To say the least, this is only scratching the surface.

Magic methods

PHP allows us to declare several so-called magic methods in a class. Magic - because we don't even have to call them (even though we technically can). They are called automatically at specific points during runtime. In other words, they react to events. Every magic method starts with a double underscore. They are lots of them, but we will only go over the three main ones in this lesson.

Constructor

First of all, we create an empty (uninitialized) Human instance, then we set the first and last name, and age. Setting things this way has many disadvantages, namely:

  1. You are able to create an uninitialized instance and work with it, which will cause errors for sure, e.g. when you try to print out the instance's first name, which has not been set.
  2. Setting up individual values takes up a lot of space in the source code.

These issues can be addressed by adding a custom constructor. A constructor is a method that is automatically called when the instance is created. We use them to initialize an object's inner state in a stable and proper way. When a class has a constructor defined, that leaves no other way to create instances other than using said constructor.

Constructors are declared by adding a function and naming it __construct() and adding an arbitrary number of parameters. Let's add one to our class with the following parameters: $firstName, $lastName, and $age. Here, we assign values to the current instance's attributes based on the given parameters:

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

Make sure you declare the constructor after the attribute declarations and before any other method. If you run the application now, it won't work. This is because our instance initializations in our main PHP file are out of date. PHP doesn't allow for object initialization other than how the constructor has been defined.

Let's move to index.php, where we will add the required parameters to the instance initializations:

require_once('classes/Human.php');

$carl = new Human('Carl', 'Smith', 30);
$john = new Human('John', 'Newman', 24);

$carl->greet();
echo('<br />');
$john->greet();
echo('<br />');
class Human
{

    public $firstName;
    public $lastName;
    public $age;

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

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

As you can plainly see, the code is much clearer. Parentheses that follow the class name are used to pass parameters to the constructor. The constructor then stores these values into the object and prepares it for use. Constructor usage is not limited to attributes initialization, you could do anything and everything that could be done in a regular method. Constructors can even be defined without parameters, which is useful if all we wanted to do is store the time when the instance was created, among other things.

Destructor

For completeness sake, I will briefly go over destructors as well. As you may have guessed, destructors are methods that are called when the object is removed from memory. We could perform clean-up routines, i.e. freeing resources, that were used by the object. PHP scripts only run for a short amount of time, after which the entire memory used by the script, is freed. In other words, destructors are not very important. Although we could use them to store data into a database before destroying the object or to disconnect from a database before being destroyed, etc. You probably won't find any use for destructors at the moment, however, it is related to the constructor so why not test it out?

Destructor methods must be named __destruct(). We'll print out a message when an object is removed from memory:

public function __destruct()
{
    echo("I've been removed from memory.");
}
require_once('classes/Human.php');

$carl = new Human('Carl', 'Smith', 30);
$john = new Human('John', 'Newman', 24);

$carl->greet();
echo('<br />');
$john->greet();
echo('<br />');

If you run the application now, at the very bottom, you will find the text we defined printed out twice:

Your page
localhost

This message will be printed from both $carl and $john when they are removed as the application terminates, or more accurately when there is no reason to keep them in memory.

Just to be clear, adding a destructor to your classes is not necessary.

ToString

The magic __toString() method is called when we need to convert an object to a string, in most cases, to print it out. Let's go ahead and try to print out the $carl object:

echo($carl);

You will get a PHP error, due to the fact humans do not have a defined way to be printed out. Humans are objects with several properties, which leaves PHP with no idea of which one of them to print out. Let's add a __toString() method in our Human class that returns an instance's $firstName attribute.

public function __toString()
{
    return $this->firstName;
}
require_once('classes/Human.php');

$carl = new Human('Carl', 'Smith', 30);
$john = new Human('John', 'Newman', 24);

echo($carl);

Now, when you try to print out Carl or John, their first names will be displayed.

Constructors also allow us to encapsulate data, which we will look into next time - Solved tasks for OOP in PHP lessons 1-3. Today's project can be downloaded in the attachment below, as always.

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


 

Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.

Download

By downloading the following file, you agree to the license terms

Downloaded 52x (1.69 kB)
Application includes source codes in language PHP

 

Previous article
First object-oriented application in PHP
All articles in this section
Object-Oriented Programming in PHP
Skip article
(not recommended)
Solved tasks for OOP in PHP lessons 1-3
Article has been written for you by David Capka Hartinger
Avatar
User rating:
4 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