In our Overview of WordPress and Object-Oriented Programming we ran through the theory behind Object-Oriented Programming (OOP) and what to expect when using it.
Before we proceed with more specific coding examples using OOP, in this article we will try to explain how a real world scenario can be approached with the different mindset required for OOP and how this is analyzed using objects and classes.
A Real Life Scenario: Sending an SMS
This is more like, a “past” life scenario actually as SMS is used less and less nowadays but as you’ll see, there is a reason we use this as an example!
Suppose you have a mobile device and you want to send a text message to one of your contacts. Keeping the example as simple as possible, the sequence of actions would be:
- Prepare the message
- Select one of your contacts and add as a recipient
- Send the message
So let’s try and visualize the steps that you would follow in order to send your message:
We added some more detailed descriptions of the actions but more or less all that you do is 3 basic steps. You prepare the message in the device editor, you select the recipient from your contacts, and then send the message. And you are done! Your message is now sent.
Now, if we were to represent in code an application that sends an SMS message we should analyze which route is better to follow; the procedural or OOP approach.
The Application with a Procedural Approach
If you’re a WordPress plugin developer, you’re most likely familiar with procedural programming.
As we described previously, procedural programming is a type of imperative programming, where our programs consist of one or more procedures. So, as a developer you break down your plugin into a bunch of variables that hold your data, and functions that operate on the data.
In our example above with the SMS message, you would perform a series of actions that would lead to the desired result. As you may have already guessed, you would have, for example, a variable that holds the message’s text content, a function with a $contact
parameter that returns the phone number and finally, a function that sends the message. In code it would look like this:
function get_phone_number( $contact ) {
// Code that finds the contact's number in the list of contacts
return $phone_number;
}
function send_sms( $contact, $message ) {
$phone_number = get_phone_number( $contact );
// Code that sends the message to this number
print "Message Sent!";
}
And you would use it like this:
$text = "Hello John";
function send_message( "John Doe", $text );
So, you would complete a series of tasks that will lead you to the desired result.
In this very simple example of course, that has limited and very specific requirements, there is no reason to consider using OOP at all. Procedural programming is more than enough to achieve your goal. But, if you think of some scenarios as to how this application could expand in the future, you might realize that, in the long run, you could have issues in terms of scalability. We will try and explain why below.
Expanding the Application with Procedural Approach
Let’s say that you want to improve this application and provide the ability to send other kinds of messages as well, like an email for example. The function that delivers the message would be different in each case.
Try our Award-Winning WordPress Hosting today!
When sending an email, you need the contact’s email address, not the phone number. Apart from this, we will need to add a parameter in the final send_message()
function that will correspond to the type of technology we use; email or SMS.
The corresponding code could look something like this:
function get_phone_number( $contact ) {
// Code that finds the contact's number
return $phone_number;
}
function get_email_address( $contact ) {
// Code that finds the contact's email address
return $email_address;
}
function send_sms( $contact, $message ) {
$phone_number = get_phone_number( $contact );
// Code that sends the message to this number
print "SMS Sent!";
}
function send_email( $contact, $message ) {
$email_address = get_email_address( $contact );
// Code that sends the email to this number
print "Email Sent!";
}
function send_message( $contact, $message, $technology ) {
if ( $technology == "SMS") {
send_sms( $phone_number, $message );
} else if ( $technology == "Email") {
send_email( $email_address, $message );
}
}
So, it is not like this could not be implemented with a procedural approach. But if you are an experienced developer you’ve probably already understood how this could become messy in the future.
The Drawbacks with a Procedural Approach
What if we had multiple types of messages? The if
statements would become annoyingly large. And, most importantly, what if you had functions that use the send_message()
function? In that case, you would need to add the $technology
parameter in all those functions as well.
As your code grows, functions will be all over the place meaning you will be starting to copy/paste chunks of code (never desirable), and making a small change to a function might break several other functions. We’ve all been there. You would want to avoid this and be able to easily add features to your code without interfering in the structure too much.
Object-oriented programming (or OOP) is a programming paradigm that attempts to solve this issue by allowing us to structure our plugin into small, reusable pieces of code, called classes. As we described in our OOP Overview article, a class is basically a template that we use to create individual instances of the class, called objects.
An object contains data and code. We still have variables that can store information, called properties. And procedures that operate on the data, called methods.
The Application with an OOP Approach
Now let’s analyze the same scenario as above with an OOP approach.
First, we will define what objects we have here, what characteristics each has and what actions they perform. The characteristics are what later will be our properties and actions will be our functions or methods as they are called in OOP.
Let’s think about what we have in the first scenario of sending an SMS in the simplest way possible. There is a device which has an interface that we use to send the SMS message. We have the message content, we choose a contact as a recipient and finally the message.
<?php
/**
* Plugin Name: Send Message
*/
interface MessagingCapable {
public function send_message( $contact, $message );
}
class Phone implements MessagingCapable {
public function send_message( $contact, $message ) {
print "You sent" . $message ;
}
}
function say_hi( MessagingCapable $device, $contact, $message ) {
$device->send_message( $contact, $message );
}
We declare the Phone
class which implements the MessagingCapable
interface. So we have to implement all the methods declared in it. The say_hi()
function requires 3 parameters:
- A device that supports messaging
- A contact
- The message
In order to actually send a message we use this function like this:
$phone = new Phone();
say_hi( $phone, "John Doe", "Hello John" );
We are basically creating an object by instantiating the Phone class and passing the contact and message content. This would output:
You sent "Hello John"
We demonstrated this simple scenario of sending an text message by using classes. In the next section, we will see how we can expand the application’s capabilities following the OOP approach and while scaling up, we will examine where the OOP features play their role as well as the benefits of using this technique.
Expanding the Application with the OOP approach
Let’s add the ability to send emails as well, like we did before procedurally.
Regardless of the device, we ideally would want to use the say_hi()
function the same way. Take a look at code below:
<?php
/**
* Plugin Name: Send Message
*/
interface MessagingCapable {
public function send_message( $contact, $message );
}
class Phone implements MessagingCapable {
public function send_message( $contact, $message ) {
print ('You sent a "' . $message . '" SMS to ' . $contact );
}
}
class Computer implements MessagingCapable {
public function send_message( $contact, $message ) {
print ('You sent a "' . $message . '" email to ' . $contact );
}
}
function say_hi( MessagingCapable $device, $contact, $message ) {
$device->send_message( $contact, $message );
}
When we use this piece of code, we would pick up the mobile device to send an SMS and the computer to send an email. We would either:
say_hi ( new Phone(), "John Doe", "Hello John" );
or:
say_hi ( new Computer(), "John Doe", "Hello John" );
that would output You sent a "Hello John" SMS to John Doe
and You sent a "Hello John" email to John Doe
correspondingly.
Here we already start to detect some OOP features. We introduced interfaces by using the MessagingCapable
interface.
An interface declares a set of methods that must be implemented by the class without defining how these methods are implemented. All methods declared in an interface must be public.
PHP doesn’t support multiple inheritance, meaning a class cannot inherit the properties/methods of multiple parent classes.
While it can only extend one class, it can implement multiple interfaces.
Using a Phone to send a message will be different from using a Computer. Instances of different classes act differently when asked to perform the same action (i.e. send_message()
). This is an example of Polymorphism. If we later create a new device, we won’t need to modify our code to accommodate it, as long as they all share the same interface.
We would also like to point out here that we already see the difference in readability as well. The way we finally use this script by just coding:
say_hi( new Computer(), "John", "Hi" );
This is totally straightforward to any developer that works on the project. And of course, the more complex the plugin, it becomes more obvious how helpful this is, especially when working in a team.
To try and explain better how easy it is to expand your plugin in Object-Oriented Programming let’s try adding some more functionality.
Adding More Functionality
If we want to add the ability to browse the internet, we would just add an extra interface for any device that could respond to this ability, like a computer for example.
interface InternetBrowsingCapable {
public function visit_website( $url );
}
The implementation of this interface will be coded like this:
class Computer implements MessagingCapable, InternetBrowsingCapable {
public function send_message( $contact, $message ) {
print ('You sent a "' . $message . '" email to ' . $contact );
}
public function visit_website( $url ) {
print ('You visited "' . $url );
}
}
So in the current Computer class we just added the extra interface to be implemented, since a computer can send a message and browse the internet, and the visit_website( $url )
method.
NOTE: Of course, since visiting a url is totally irrelevant with the say_hi()
function we will also introduce a new function, something like:
function visit_url( InternetBrowsingCapable $device, $url ) {
$device->visit_website( $url );
}
And that’s it! For any device that can visit a URL we can use this function like we did with computer. There are no worries that you will break the rest of functionality. This shows the scalability available when using OOP compared to procedural programming.
Let’s add a smartphone device just to demonstrate some more features. Here is the whole code, with the smartphone class addition so that you can have a better picture of what’s going on:
<?php
/*
* Plugin Name: Communication Plugin
*/
interface MessagingCapable {
public function send_message( $contact, $message );
}
interface InternetBrowsingCapable {
public function visit_website( $url );
}
class Phone implements MessagingCapable {
public function send_message( $contact, $message ) {
print 'You sent a "' . $message . '" SMS to ' . $contact;
}
}
class Computer implements MessagingCapable, InternetBrowsingCapable {
public function send_message( $contact, $message ) {
print 'You sent a "' . $message . '" email to ' . $contact;
}
public function visit_website( $url ) {
print 'You visited "' . $url;
}
}
class Smartphone extends Phone implements InternetBrowsingCapable {
public function visit_website( $url ) {
print 'You visited "' . $url;
}
public function send_message( $contact, $message ) {
parent::send_message( $contact, $message );
print ' from your smartphone';
}
}
function say_hi( MessagingCapable $device, $contact, $message ) {
$device->send_message( $contact, $message );
}
function visit_url( InternetBrowsingCapable $device, $url ) {
$device->visit_website( $url );
}
The Smartphone class extends the Phone parent class and implements the InternetBrowsingCapable
interface. That means it can send a message and visit a URL. Here, we detect the Inheritance feature. In other words, we have an hierarchy of classes, a parent class(Phone) and a subclass(Smartphone).
So a Smartphone object inherits all the properties and behaviors of the parent Phone class. That way, inside the child class we can add a method or override a method of the parent class, like we did with the send_message()
in the Smartphone class. We did this to change the output. We could totally ignore this method and use the send_message()
of the parent class as it is.
You can try the code yourself by pasting it in the code block to this great PHP online tool. Under the code, try any of these code lines and see the different results.
say_hi ( new Phone(), "John Doe", "Hello John" );
say_hi ( new Computer(), "John Doe", "Hello John" );
say_hi ( new Smartphone(), "John Doe", "Hello John" );
visit_url ( new Smartphone(), "https://www.pressidium.com" );
visit_url ( new Computer(), "https://www.pressidium.com" );
For an even better understanding of the whole concept take a look at the Class diagram of the above code.
As depicted above, when designing the relationships between classes, we do not include the common elements in the child class. Furthermore, do not forget to pay attention in the guide on the left so you can identify the relationships and the visibility of their properties and methods.
If you would like to see the Encapsulation feature in action as well, try and include a Contact class in any of the above example scripts we provided. The class would look like this:
class Contact {
private $name;
private $phone_number;
private $email_address;
public function __construct( $name, $phone_number, $email_address ) {
$this->name = $name;
$this->phone_number = $phone_number;
$this->email_address = $email_address;
}
public function get_name() {
return $this->name;
}
public function get_phone_number() {
return $this->phone_number;
}
public function get_email_address() {
return $this->email_address;
}
}
The __construct()
method, by design, is called automatically upon the creation of an object. Now when we instantiate the Contact class, its constructor gets called and sets the values of its private properties. Then we use our “getters” that are the get_name()
, get_phone_number()
and get_email_address()
public methods to retrieve these values.
Encapsulation is bundling the data with the methods that operate on the data while restricting direct access preventing exposure of hidden implementation details.
Conclusion
Hopefully this article helped you understand Object-Oriented programming in a more practical way. OOP really helps make it easier for the application to expand in the future if necessary by being clear and reusable.
In addition a plugin that uses OOP will be faster and easier to execute. That is because the methods that are common for all objects of a class consume memory only once, during their declaration.
Security is also improved because of encapsulation. In procedural programming on the other hand, all data is global which means access is available from anywhere.
As a result of the above, code maintenance, productivity, scalability and troubleshooting also become much easier for you and your team.
In the next articles of this series we will see this programming style in action by applying it to a WordPress plugin. Specifically, we will create a copy of the Limit Login Attempts plugin version 1.7.1 created by Johan Eenfeldt but converted with an Object-Oriented approach as much as possible.
During this process, we’ll break down the plugin flow and set the requirements. Going forward, we’ll try out our first thoughts on the plugin’s design and, in the implementation step, we’ll write the code. During the implementation process we’ll make some back’n’forths and redesign, if necessary, in order to get the desired results.
We’ll not get into details on all parts of the code though. Instead, we would like to focus on sharing the way plugins are built the Object-Oriented way. We are confident that, once you’ve finished reading this article series, you can very well create an OOP plugin of your own.
Click here to read Part 3 in our Objected Oriented Programming Series where we explain how you can define the requirements of your OOP plugin.
See Also
- Summary of the series
- Part 1 – WordPress and Object-Oriented Programming – An Overview
- Part 4 – WordPress and Object Oriented Programming: A WordPress Example – Design
- Part 5 – WordPress and Object Oriented Programming: A WordPress Example – Implementation: The Administration Menu
- Part 6 – WordPress and Object Oriented Programming: A WordPress Example – Implementation: Registering the Sections
- Part 7 – WordPress and Object Oriented Programming: A WordPress Example – Implementation: Managing WordPress Hooks
- Part 8 – WordPress and Object Oriented Programming: A WordPress Example – Implementation: Options
Start Your 14 Day Free Trial
Try our award winning WordPress Hosting!