Mastering Object Oriented Programming in PHP

Introduction to OOP in PHP

Last Updated on November 07, 2023 15 min read

Hiiiii. Welcome to my tutorial series on "Mastering Object-Oriented Programming in PHP"! You are precisely where you need to be, whether you are a seasoned PHP developer eager to learn more about Object-Oriented Programming (OOP) or a beginner. This first article is basically for setting the stage for an exhilarating adventure into OOP.

Table of contents

Prerequisites

Before you begin, you must understand the fundamentals of PHP. You should be comfortable with basic PHP concepts such as variables, functions, and control structures. If you've worked with PHP code before, even if it was only the basic "Hello, World!" script, you're in a terrific position to join me on this voyage. Let's GO!

What is Object-Oriented Programming (OOP)?

"What exactly is this OOP thing, what's the big deal with it, and why should I bother?" you may wonder. In actuality, you may already be making use of OOP without even recognizing it. Object-Oriented Programming (OOP) is a programming paradigm that revolves around the concept of "objects". In OOP, nearly everything is considered an object.

Imagine you're in a charming bakery and inside; they're making a variety of cakes — chocolate, vanilla, and red velvet (by the way, who can resist a good cake?). Each of these cakes has its own unique ingredients and a step-by-step guide on how to bring it to life.

Now, picture OOP as a recipe book for these cakes. In OOP, you're the chef who creates classes—these are like your recipe templates. Each class acts as a baking blueprint, specifying the ingredients (properties) required and the steps (methods) to whip up a particular type of cake.

Every time you want to make cake, all you have to do is grab the recipe (class) you need from your cookbook and follow the instructions to craft the cake (object). The beauty of it is that each cake you bake will have a unique flavor and set of features, and they will all be prepared according to the same recipe (or class).

For now, don't worry about the jargon in the brackets; we'll come to it later, and it'll all make sense 🤗.

A Bit of History

OOP isn't a new concept, it's been around since the 1960s. However, it truly caught fire in the programming world during the 1990s and has since become a fundamental approach. Languages like C++ and Java played pivotal roles in pushing OOP into the limelight.

This surge in interest was partly driven by the growing complexity of software systems. As applications grew larger and more intricate, developers needed a more effective way to manage and organize their code.

In PHP, OOP support made its debut in version 4. However, it wasn't until PHP 5 that it truly established itself as a powerful and essential feature of the language. It allowed PHP devs to create classes, work with objects, and fully reap the benefits of Object-Oriented Programming. We've come a long way since then, and there's been so many changes since the days of PHP 5, but we'll get to those later in this series.

Setting Up Your PHP Development Environment

Before we dive into coding, please make sure you've set up a suitable PHP development environment. There are multiple options to choose from. You can go the easy route with tools like XAMPP, Herd, WAMP, or Laragon for a hassle-free setup. Alternatively, if you're more technically inclined, set up PHP and a web server manually (Go Dev!!!). Docker enthusiasts can spin up a PHP container (I have a guide on that so check it out), while IDE lovers can opt for Visual Studio Code with the PHP Server extension. Your choice depends on your comfort level and preferences, but rest assured, I'll guide you through OOP with whichever setup you choose.

Creating Your First PHP Class

Before we construct our first class, let's define what classes and objects are in the actual world, not only in programming.

What is an Object?

In everyday life, objects can be anything from tangible, like cars, houses, and phones, or intangible, like a bank account, an e-commerce order, or a user profile. Objects are typically defined by their state (attributes) and behavior (actions).

  1. Car:
    • State: color, number of tires, tinted or not tinted, manual or automatic, etc
    • Behavior - accelerate, brake, turn, etc.
  2. Phones:
    • State: model, OS, screen size, battery capacity, etc.
    • Behavior - make calls, send messages, open app, take picture.
  3. Bank Account:
    • State: account holder's name, account number, balance, account type.
    • Behavior - deposit, withdraw, check balance, etc.
  4. User Profile:
    • State: fullname, username, email, profile picture, number of followers, posts and comments.
    • Behavior - post content, like a post, comment on post, follow user, etc.

What is a class?

A class in programming is like a blueprint in the real world. It defines the structure and behavior that objects will have when created from it. Just as various car models share common features like tyres, steering wheel, and a chassis, despite having different properties, classes establish a common structure for objects.

For instance, consider a class for a Smartphone. This class defines properties such as model, operating system, screen size, and battery capacity. It also defines methods like makeCall, sendText, and takePicture.

From this class, you can create multiple objects, each with its unique values for these properties while sharing the same set of behaviors (methods). So, an iPhone 15 Pro and a Samsung S23 Ultra may have different property values but are both instances of the Smartphone class, equipped with the same methods to make calls, send texts, and take pictures.

Creating a new PHP class

In PHP, you create a new class using the class keyword. You are free to use any acceptable identifier when naming your new class. However, the UpperCamelCase naming convention is usually recommended. The term UpperCamelCase refers to the convention that class names begin with an uppercase letter and capitalize the first letter of each word if the name is composed of multiple words. For example, SmartPhone, BankAccount, and Cake. It's a widely accepted practice that enhances code readability and consistency.

If you'd like to delve deeper into coding standards in PHP (something I wish many PHP developers will take to heart), you can go through the PSR standards, where you'll see a lot of guidelines for clean PHP coding, including naming conventions.

Now, let's relate all these to my analogy earlier of baking cakes. Just as we identified the common attributes (state) and actions (behavior) of real-world objects, we'll do the same for our Cake class. We'll create a class that defines what a cake is, specifying its properties (like flavor and layers) and methods (like baking).

class Cake {
    // Properties
    public $flavor;
    public $layers = 1;

    // Methods
    public function bake()
    {
        return "Baking a $this->flavor cake with $this->layers layer(s)!";
    }
}

With this Cake class, we've defined the state and behavior of a cake in our code. Just like a real-world object, our Cake class can have different flavors and layers, and it can be baked using the bake() method.

Creating a new PHP object

Now that we've created our Cake class, we can create multiple cakes from it. In OOP, we refer to these cakes as Objects. Objects are instances of a class. They are created using the new keyword, followed by the class name and parentheses.

Let's create some cakes from our Cake class:

// Create cake instances
$chocolateCake = new Cake();
$redVelvetCake = new Cake();

// Change cake properties
$chocolateCake->flavor = "chocolate";
$redVelvetCake->flavor = "red velvet";
$redVelvetCake->layers = 2;

// Bake the cakes
echo $chocolateCake->bake(); // Output: Baking a chocolate cake with 1 layer(s)!
echo $redVelvetCake->bake(); // Output: Baking a red velvet cake with 2 layer(s)!

Properties and Methods

In an ordinary PHP file, properties are equal to variables, but when they are inside a class, we call them properties. Similarly, methods in a class are identical to functions in a conventional PHP file, but they are referred to as methods within a class.

You can access and modify properties using the arrow ( ->) notation (a subtle borrow from C++). To access a property, use $object >property, and to call a method, use $object->method().

For instance, to change the flavor of a cake:

$chocolateCake->flavor = "chocolate";

And to bake a cake:

echo $chocolateCake->bake();

Properties can have default values, as shown in our Cake class. Methods can perform various actions and return results, making them versatile tools for encapsulating behavior.

The $this Keyword

IF you're observant, or entirely new to OOP, you may have noticed the use of the $this keyword in our Cake class. $this is a special keyword that refers to the current object. It's used to access properties and methods within a class (remember, within!!!). For instance, in our Cake class, we used $this->flavor to access the flavor property and $this->layers to access the layers property.

You cannot use $this outside a class. It's only available within a class.

Why Should I Use Object-Oriented Programming (OOP)?

Now that you have a basic understanding of what PHP classes and objects look like, you may be wondering, "Why should I care about OOP in PHP?" Or should we ask "Is OOP really necessary?" The truth is that OOP is more than simply a programming paradigm; it is a reflection of how we think and interact with the world as humans. We humans relate to the world through objects, each with its attributes and the relationships that verbs establish.

Consider this sentence

Kyrian has a laptop

We've instantly identified two objects, "Kyrian" and "a laptop." These two objects have their states and behaviors

  • Kyrian:
    • State: firstname, lastname, age, height, eye color, skin color, etc
    • Behavior - walk, run, sleep, eat, write, sing, etc.
  • a laptop:
    • State: model, name, screen size, resolution, ram, processor, etc.
    • Behavior - turn on, turn off, sleep, calculate, store data, display data, etc.

We've also identified a relationship between these two objects—The verb "has." While they both have their functionality within them and can perform various actions, they can also interact with each other. For instance, Kyrian can use the laptop to write a book, and the laptop can store the book.

This is the essence of OOP. OOP builds upon this very concept. It resonates with how we naturally perceive the world, allowing us to design computer solutions that align with our thought process.

Computers work differently than we do. They don't understand the world in terms of objects, attributes, and relationships. Instead, they work with bits and bytes, 1s and 0s. So naturally, we develop abstractions to interact with them in a way that makes sense to us (thus, the birth of programming languages). For example, we need folders to organize and make sense of our files; computers don't necessarily need them.

The functional paradigm, which is the most common programming paradigm, is an excellent abstraction for computers. It's a simple, straightforward approach that allows us to write code that computers can easily understand. However, it's not the best abstraction for us humans, especially when we're working on large, complex projects. It's essentially a series of commands given to the computer, and it isn't always easy to understand what's going on.

For example, to work with shapes like circles, triangles and squares, you'd have to write code like this:

function areaOfCircle($radius)
{
    return 3.14 * $radius * $radius;
}

function areaOfTriangle($base, $height)
{
    return 0.5 * $base * $height;
}

function areaOfSquare($side)
{
    return $side * $side;
}

This is just for calculating the area of shapes. Imagine how much more code you'd have to write to work with other aspects of these shapes. It's not very intuitive nor flexible, and its complexity increases as the project grows. For instance, what if you wanted to add more information about the shapes, like their color, or you want to perform other operations on the individual shapes like perimeter, etc.? C'mon, it's not giving!!

Let's look at how we can use OOP to fix this problem. We may specify what a shape is and how it behaves by creating a Shape class. We can then develop classes that extend the Shape class for each shape. By doing so, the shape's characteristics (such as color) and behavior (such as area calculation) are defined in one location.

class Shape
{
    public $name = 'shape';

    public function __construct(public $color)
    {
    }
    
    public function area()
    {
        return 0;
    }
    
    public function info()
    {
        return "This {$this->color} {$this->name} has an area of {$this->area()}";
    }
}

class Circle extends Shape
{
    public $name = 'circle';

    public function __construct(public $color, public $radius)
    {
    }

    public function area()
    {
        return 3.14 * $this->radius * $this->radius;
    }
}

class Triangle extends Shape
{
    public $name = 'triangle';

    public function __construct(public $color, public $base, public $height)
    {
    }

    public function area()
    {
        return 0.5 * $this->base * $this->height;
    }
}

class Square extends Shape
{
    public $name = 'square';

    public function __construct(public $color, public $side)
    {
    }

    public function area()
    {
        return $this->side * $this->side;
    }
}

$redCircle = new Circle('red', 5);
$yellowCircle = new Circle('yellow', 10);
$blueTriangle = new Triangle('blue', 10, 5);
$purpleTriangle = new Triangle('purple', 20, 10);
$greenSquare = new Square('green', 10);
$blackSquare = new Square('black', 20);


echo $redCircle->info() . "\n"; // Output: This red circle has an area of 78.5
echo $yellowCircle->info() . "\n"; // Output: This yellow circle has an area of 314
echo $blueTriangle->info() . "\n"; // Output: This blue triangle has an area of 25
echo $purpleTriangle->info() . "\n"; // Output: This purple triangle has an area of 100
echo $greenSquare->info() . "\n"; // Output: This green square has an area of 100
echo $blackSquare->info() . "\n"; // Output: This black square has an area of 400

This code is far more natural and more in line with how humans actually conceptualize shapes. It is also incredibly flexible. We can do a tonne of stuff with this code. For instance, we can add more shapes like rectangles, pentagons, and hexagons. We can also add more information about a shape, e.g., number of sides. We can even add more behavior like calculating the perimeter of the shapes. The possibilities are endless. That's the power of OOP. Principles like encapsulation, inheritance, and polymorphism were demonstrated here (e.g., notice that the info() method is defined only in the Shape class but was invoked by all the other classes), but we'll get to those later in this series.

Let's look at another example. Consider a simple program that stores information about books and displays them to the user. Here's how we'd do it without OOP:

$book1 = [
    'title' => 'The Alchemist',
    'author' => 'Paulo Coelho',
    'pages' => 197,
    'read' => true
];

$book2 = [
    'title' => 'The 5 AM Club',
    'author' => 'Robin Sharma',
    'pages' => 336,
    'read' => false
];

$book3 = [
    'title' => 'The Monk Who Sold His Ferrari',
    'author' => 'Robin Sharma',
    'pages' => 198,
    'read' => true
];

$books = [$book1, $book2, $book3];

foreach ($books as $book) {
    if ($book['read']) {
        echo "You've read all {$this->pages} of  {$this->title} by {$this->author}. Great job!\n";
    } else {
        echo "{$this->title} by {$this->author} is a great book with {$this->pages} pages. You should read it!";
    }
}

This code is pretty straightforward, but it's not very intuitive. It's not easy to tell what's going on, and it's not very flexible. For instance, what if we wanted to add more information about the books, like the year they were published? We'd have to update the code in multiple places, which is not ideal.

Now, let's see how we can use OOP to solve this problem:

class Book
{
    public function __construct(
        public $title, 
        public $author, 
        public $pages, 
        public $read)
    {
    }

    public function info()
    {
        return $this->read ?
            "You've read all {$this->pages} of  {$this->title} by {$this->author}. Great job!" :
            "{$this->title} by {$this->author} is a great book with {$this->pages} pages. You should read it!";
    }
}

$book1 = new Book('The Alchemist', 'Paulo Coelho', 197, true);
$book2 = new Book('The 5 AM Club', 'Robin Sharma', 336, false);
$book3 = new Book('The Monk Who Sold His Ferrari', 'Robin Sharma', 198, true);

echo $book1->info() . "\n"; // Output: You've read all 197 of  The Alchemist by Paulo Coelho. Great job!
echo $book2->info() . "\n"; // Output: The 5 AM Club by Robin Sharma is a great book with 336 pages. You should read it!
echo $book3->info() . "\n"; // Output: You've read all 198 of  The Monk Who Sold His Ferrari by Robin Sharma. Great job!

And again, we have a more elegant solution that's natural to our way of thinking. We've created a Book class that defines what a book is and how it behaves. If you noticed, everything about the book has been encapsulated within the Book class. We've defined the book's properties (title, author, pages, and read) and its behavior (isRead and info). Beautiful, isn't it?

And that's it for a start. We've captured the essence of creating classes and objects in PHP, but we're just getting started with what classes and objects can do. In the next tutorial of this series, we'll explore classes and objects in more detail, dive into constructors, and continue building our understanding of OOP in PHP. But for now, enjoy experimenting with your freshly baked cakes and your new books. See you in the next tutorial!