Properties and methods visibility

So far, all the properties and methods defined in our Book class were tagged as public. That means that they are accessible to anyone, or more precisely, from anywhere. This is called the visibility of the property or method, and there are three types of visibility. In the order of being more restrictive to less, they are as follows:

  • private: This type allows access only to members of the same class. If A and B are instances of the class C, A can access the properties and methods of B.
  • protected: This type allows access to members of the same class and instances from classes that inherit from that one only. You will see inheritance in the next section.
  • public: This type refers to a property or method that is accessible from anywhere. Any classes or code in general from outside the class can access it.

In order to show some examples, let's first create a second class in our application. Save this into a Customer.php file:

<?php

class Customer {
    private $id;
    private $firstname;
    private $surname;
    private $email;

    public function __construct(
        int $id,
        string $firstname,
        string $surname,
        string $email
    ) {
        $this->id = $id;
        $this->firstname = $firstname;
        $this->surname = $surname;
        $this->email = $email;
    }
}

This class represents a customer, and its properties consist of the general information that the bookstores usually know about their customers. But for security reasons, we cannot let everybody know about the personal data of our customers, so we set every property as private.

So far, we have been adding the code to create objects in the same Book.php file, but since now we have two classes, it seems natural to leave the classes in their respective files, and create and play with objects in a separate file. Let's name this third file init.php. In order to instantiate objects of a given class, PHP needs to know where the class is. For that, just include the file with require_once.

<?php

require_once __DIR__ . '/Book.php';
require_once __DIR__ . '/Customer.php';

$book1 = new Book("1984", "George Orwell", 9785267006323, 12);
$book2 = new Book("To Kill a Mockingbird", "Harper Lee", 9780061120084, 2);

$customer1 = new Customer(1, 'John', 'Doe', '[email protected]');
$customer2 = new Customer(2, 'Mary', 'Poppins', '[email protected]');

You do not need to include the files every single time. Once you include them, PHP will know where to find the classes, even though your code is in a different file.

Note

Conventions for classes

When working with classes, you should know that there are some conventions that everyone tries to follow in order to ensure clean code which is easy to maintain. The most important ones are as follows:

  • Each class should be in a file named the same as the class along with the .php extension
  • Class names should be in CamelCase, that is, each word should start with an uppercase letter, followed by the rest of the word in lowercase
  • A file should contain only the code of one class
  • Inside a class, you should first place the properties, then the constructor, and finally, the rest of the methods

To show how visibility works, let's try the following code:

$book1->available = 2; // OK
$customer1->id = 3; // Error!

We already know that the properties of the Book class' objects are public, and therefore, editable from outside. But when trying to change a value from Customer, PHP complains, as its properties are private.

Encapsulation

When working with objects, one of the most important concepts you have to know and apply is encapsulation. Encapsulation tries to group the data of the object with its methods in an attempt to hide the internal structure of the object from the rest of the world. In simple words, you could say that you use encapsulation if the properties of an object are private, and the only way to update them is through public methods.

The reason for using encapsulation is to make it easier for a developer to make changes to the internal structure of the class without directly affecting the external code that uses that class. For example, imagine that our Customer class, that now has two properties to define its name—firstname and surname—has to change. From now on, we only have one property name that contains both. If we were accessing its properties straightaway, we should change all of those accesses!

Instead, if we set the properties as private and enable two public methods, getFirstname and getSurname, even if we have to change the internal structure of the class, we could just change the implementation of those two methods—which is at one place only—and the rest of the code that uses our class will not be affected at all. This concept is also known as information hiding.

The easiest way to implement this idea is by setting all the properties of the class as private and enabling two methods for each of the properties: one will get the current value (also known as getter), and the other will allow you to set a new value (known as setter). That's at least the most common and easy way to encapsulate data.

But let's go one step further: when defining a class, think of the data that you want the user to be able to change and to retrieve, and only add setters and getters for them. For example, customers might change their e-mail address, but their name, surname, and ID remains the same once we create them. The new definition of the class would look like the following:

<?php

class Customer {
    private $id;
    private $name;
    private $surname;
    private $email;

    public function __construct(
        int $id,
        string $firstname,
        string $surname,
        string $email
    ) {
        $this->id = $id;
        $this->firstname = $firstname;
        $this->surname = $surname;
        $this->email = $email;
    }

    public function getId(): id {
        return $this->id;
    }
    public function getFirstname(): string {
        return $this->firstname;
    }
    public function getSurname(): string {
        return $this->surname;
    }
    public function getEmail(): string {
        return $this->email;
    }
    public function setEmail(string $email) {
        $this->email = $email;
    }
}

On the other hand, our books also remain almost the same. The only change possible is the number of available units. But we usually take or add one book at a time instead of setting the specific number of units available, so a setter here is not really useful. We already have the getCopy method that takes one copy when possible; let's add an addCopy method, plus the rest of the getters:

<?php

class Book {
    private $isbn;
    private $title;
    private $author;
    private $available;

    public function __construct(
        int $isbn,
        string $title,
        string $author,
        int $available = 0
    ) {
        $this->isbn = $isbn;
        $this->title = $title;
        $this->author = $author;
        $this->available = $available;
    }
    public function getIsbn(): int {
        return $this->isbn;
    }
    public function getTitle(): string {
        return $this->title;
    }
    public function getAuthor(): string {
        return $this->author;
    }
    public function isAvailable(): bool {
        return $this->available;
    }

    public function getPrintableTitle(): string {
        $result = '<i>' . $this->title . '</i> - ' . $this->author;
        if (!$this->available) {
            $result .= ' <b>Not available</b>';
        }
        return $result;
    }

    public function getCopy(): bool {
        if ($this->available < 1) {
            return false;
        } else {
            $this->available--;
            return true;
        }
    }

    public function addCopy() {
        $this->available++;
    }
}

When the number of classes in your application, and with it, the number of relationships between classes increases, it is helpful to represent these classes in a diagram. Let's call this diagram a UML diagram of classes, or just an hierarchic tree. The hierarchic tree for our two classes would look as follows:

Encapsulation

We only show public methods, as the protected or private ones cannot be called from outside the class, and thus, they are not useful for a developer who just wants to use these classes externally.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.210.91