The definitive guide to object-oriented programming in PHP
Honeybadger Staff
Posted on April 1, 2024
This article was originally written by Adebayo Adams on the Honeybadger Developer Blog.
Organizing your code properly is a time-saver when building large applications and working across teams as a programmer. You should always strive to write organized, reusable, and, most importantly, maintainable code so that you can work efficiently across teams with fewer conflicts during development. In this article, you will learn everything you need to know about object-oriented programming and its benefits in your PHP code.
Prerequisites
To follow along with this article, you only need to know the basics of PHP. You should be familiar with some concepts, such as variables, functions, conditional statements, and loops.
Object-oriented programming in PHP
Object-oriented programming (OOP) is a programming paradigm that enables developers to structure and treat their applications like real-world objects by using classes to bundle data and functions in a single unit and using it throughout the application, thereby improving readability, reusability, maintainability, and more.
Aside from being one of the most popular programming paradigms, it is also the most used in PHP. Most PHP frameworks and CMSs, such as Laravel, Drupal, Symphony, October, CodeIgniter, and many others use OOP at their core. Even parts of the world's most popular website builder, WordPress, uses OOP.
Next, let's explore how to use classes in PHP.
Classes
As mentioned in the previous section, object-oriented programming is based on classes, and we'll explore them in this section. For example, if you want to create a User
class, you can use the class
keyword:
<?php
class User {
}
?>
That's it! You've just created your first class in PHP.
Class properties
PHP allows you to add properties to classes. Class properties are variables you define within the class curly brackets { }
and can be used inside and outside the class. You can define a property inside a class:
class User {
public $name = 'John Sanders';
public $age = 25;
protected $email = 'jsanders@ml.com'
private $ssn = '123-45-6789';
}
The code above defines two public properties ($name
and $age
), one protected property ($email
), and one private property ($ssn
) inside the User
class. All class properties are defined by prefixing the property with public
, protected
, or private
keywords.
There are three levels of access in PHP. Public properties can be accessed inside and outside the class, and protected properties can be used inside the class that defines them and the classes that inherit them. In contrast, private properties can only be accessed within the class that defines them.
Class methods
You can add functions inside classes by defining them within the class' curly braces { }
:
class User {
// same as above...
function greet() {
echo 'Hello, ' . $this->name . ' and welcome to the site!';
}
}
The code above defines a greet
function that prints a message to the user. Functions can also be either public or private, and you can define public, protected, and private functions inside the class by prefixing them with either public
, protected
, or private
keywords:
class User {
// same as above...
public function getSSN() {
return $this->ssn;
}
private function setSSN($ssn) {
$this->ssn = $ssn;
}
}
The code above declares one public function, getSSN
, and one private function, setSSN.
The $this
keyword is used to access the class properties and methods inside the class, which means you have to use $this->age
instead of $age
to access the public age
property.
Creating objects
The User
class you created in the previous sections doesn't do anything yet; to use the class, you need to create an object from the class. For example, to create an object based on the User
class, you use the new
keyword:
$user = new User;
The code above created an object, user1
, using the User
class as a blueprint. You can now use the properties and functions of the user
class like this:
echo $user->name . ' is ' . $user->age . ' years old.';
echo "<br>";
echo $user->greet();
echo "<br>";
echo $user->getSSN();
echo "<br>";
The code above uses the single arrow (->
) syntax to access the properties and functions of the user
object and prints out the following in the browser:
The class you created in this section is not scalable because every object created with it will always have the same name, age, email, and SSN values. Let's explore how to make it dynamic in the following sections.
The __construct
method
PHP provides a magic method, __construct
, also known as the constructor
method. It is used inside classes to initialize properties of new objects. Let's rewrite the User
class to use a constructor method:
class User {
public $name;
public $age;
public $email;
private $ssn;
function __construct($name, $age, $email, $ssn) {
$this->name = $name;
$this->age = $age;
$this->email = $email;
$this->ssn = $ssn;
}
function greet() {
echo 'Hello, ' . $this->name . ' and welcome to the site!';
}
public function getSSN() {
return $this->ssn;
}
private function setSSN($ssn) {
$this->ssn = $ssn;
}
}
The code above creates a dynamic User
class by requiring every object to provide its name, age, email, and SSN properties upon creation. You can now create an object on the User
class:
$user1 = new User('Akanni William', 35, "williamak@ml.com", '123-45-6789');
$user2 = new User('Alabi Brandon', 25, "brandonal@cl.com", '987-65-4321');
echo $user1->name . ' is ' . $user1->age . ' years old.';
echo "<br>";
echo $user1->greet();
echo "<br>";
echo $user1->getSSN();
echo "<br>";
echo "<br>";
echo $user2->name . ' is ' . $user2->age . ' years old.';
echo "<br>";
echo $user2->greet();
echo "<br>";
echo $user2->getSSN();
The code above will print the following result using the name, age, email, and SSN properties upon object creation:
With this syntax, you can now create as many objects as you want with different details. Additionally, you will get an error if you do not provide all the properties listed inside the constructor for every object you create.
Note: Class names are case-insensitive, which means you can create a user object like this:
$user2 = new user(...
or like this:$user1 = new USer(...
. However, you should always try to be consistent with naming by using the conventional camel-case, which starts with an uppercase letter.
Chaining class methods
PHP helps developers to write concise code by allowing chain class methods. For example, if you have a class that handles login and logout, you might also want to change the user's status accordingly. Here is how you can do that in PHP:
class Twita {
function __construct(public $username, public $offlineStatus)
{
$this->username = $username;
$this->offlineStatus = $offlineStatus;
}
function login(){
echo "Welcome, " . $this->username . " to your account ";
echo "<br>";
return $this;
}
function logout(){
echo $this->username . "has logged out";
echo "<br>";
return $this;
}
function setOnlineStatus(){
$this->offlineStatus = false;
echo $this->username. "is now online";
echo "<br>";
return $this;
}
function setOfflineStatus(){
$this->offlineStatus = true;
echo $this->username. "is now offline";
echo "<br>";
return $this;
}
}
The code above declares a Twita class with username and offlineStatus properties and login, logout, setOnlineStatus, and setOfflineStatus methods. To chain the methods, you can use the single arrow (->
) syntax:
$twit = new Twita('Abolade William', true);
$twit->login()->setOnlineStatus()->logout()->setOfflineStatus();
You should get a response that looks like this:
Note: For method chaining to work, all the functions need to return $this
at the end of each function.
Common class constants
The following magic constants in PHP are especially useful when working with classes:
- The CLASS constant returns the name of the class where it is used.
- The FILE constant returns the full path of the file where it is used.
- The LINE constant returns the line where it is used.
- The METHOD constant returns the name of the method where it is used.
Here's an example of the constants inside a class:
Class Vehicle {
public $name;
public $color;
public $price;
public $brand;
function __construct($name, $color, $price, $brand) {
$this->name = $name;
$this->color = $color;
$this->price = $price;
$this->brand = $brand;
}
public function getClassConstant(){
echo "Name of class is: " .__CLASS__ . "<br>";
}
public function getFileConstant(){
echo "Full path of file is: " . __FILE__ . "<br>";
}
public function getLineConstant(){
echo "Line of code is: " . __LINE__ . "<br>";
}
public function getMethodConstant(){
echo "Name of method is: " . __METHOD__ . "<br>";
}
}
The code above defines a class Vehicle
with four properties ($name
,$color
,$price
, and $brand
) and four methods, (getClassConstant
, getFileConstant
, getLineConstant
, and getMethodConstant
) that returns the respective values of the constants. You can now use the Vehicle
class like this:
$vehicle = new Vehicle('Lexus', 'Black', 100000, 'Lexus');
$vehicle->getClassConstant();
$vehicle->getFileConstant();
$vehicle->getLineConstant();
$vehicle->getMethodConstant();
The code above should return the following:
The constants declared in the block of code above are particularly useful, especially when building developer tools and you need to print out the line of code, file, or function preventing the code from running correctly.
Comparing objects
If, for any reason, you want to compare objects of a class in PHP, you can do so with the equals operator (==
) and the strict equals operator (===
):
class Numbers {
public $num1;
public $num2;
public $num3;
function __construct($num1, $num2, $num3) {
$this->num1 = $num1;
$this->num2 = $num2;
$this->num3 = $num3;
}
function add() {
return $this->num1 + $this->num2 + $this->num3;
}
function multiply() {
return $this->num1 * $this->num2 * $this->num3;
}
function divide() {
return $this->num1 / $this->num2 / $this->num3;
}
function subtract() {
return $this->num1 - $this->num2 - $this->num3;
}
}
$numbers1 = new Numbers(10, 5, 2);
$numbers2 = new Numbers(10, 5, 2);
echo ($numbers1 == $numbers2) ? 'True' : 'False'; // True
echo ($numbers1 === $numbers2) ? 'True' : 'False'; // False
The code above defines a Numbers
class that takes in three numbers and functions that perform basic arithmetic operations on them. Then, it creates two instances of the class and compares them with the equals and strict equals operators. The first comparison will return true
because both instances hold the same values; however, the second check is strict and will return false
because the objects are of different instances.
Encapsulation in PHP
Encapsulation in programming refers to bundling related data and functionalities in a single unit. This approach improves reusability, readability, and maintainability.
Encapsulation can be achieved in PHP by using classes to organize your code. For example, if you are building an e-commerce application, you can have a class that handles user authentication and another that handles the checkout process. This allows multiple developers to collaborate and work on a project with minimal or no conflict while simultaneously focusing on different parts of the code.
Class inheritance
When developing applications using an object-oriented paradigm, you can write even lesser code using class inheritance in PHP. For example, when building an e-commerce application, you might have a class called Product
with properties like name
, price
, description
, and image
and methods like formatPrice
and addToCart
. You can create the class like this:
class Product {
public $name;
public $price;
public $desc;
public $image;
function __construct($name, $price, $desc, $image) {
$this->name = $name;
$this->price = $price;
$this->desc = $desc;
$this->image = $image;
}
final function formatPrice(){
return "$". $this->price . "<br>";
}
public function addToCart(){
return $this->name . " has been added to cart <br> <br>";
}
}
The code above defines a class Product
with four properties ($name
, $price
, $desc
, and $image
) and two methods (formatPrice
and addToCart
).
Note: The
final
keyword that precedes theformatPrice
functions means that the function cannot be overridden inside the classes that inherit theProduct
class.
You can now create multiple classes based on the Product
class:
class Laptop extends Product {
public $cpu;
public $ram;
public $storage;
function __construct($name, $price, $desc, $image, $cpu, $ram, $storage) {
parent::__construct($name, $price, $desc, $image);
$this->cpu = $cpu;
$this->ram = $ram;
$this->storage = $storage;
}
public function addToCart(){
return $this->name . " has been overidden <br> <br>";
}
public function formatLaptopSpecs(){
return $this->name . "<br>" . "i" . $this->cpu . " Processor <br>" . $this->ram . "GB RAM <br>" . $this->storage . "GB SSD <br> <br>";
}
}
class Phone extends Product {
public $os;
public $ram;
public $storage;
function __construct($name, $price, $desc, $image, $os, $ram, $storage) {
parent::__construct($name, $price, $desc, $image);
$this->os = $os;
$this->ram = $ram;
$this->storage = $storage;
}
public function formatPhoneSpecs(){
return $this->name . "<br>" . $this->os . "<br>" . $this->ram . "GB RAM <br>" . $this->storage . "GB <br> <br>";
}
}
class TV extends Product {
public $screenSize;
public $resolution;
public $refreshRate;
function __construct($name, $price, $desc, $image, $screenSize, $resolution, $refreshRate) {
parent::__construct($name, $price, $desc, $image);
$this->screenSize = $screenSize;
$this->resolution = $resolution;
$this->refreshRate = $refreshRate;
}
public function formatTVSpecs(){
return $this->name . "<br>" . "Screen Size: " . $this->screenSize . "<br>" . "Resolution: " .$this->resolution . "<br>" . "Refresh Rate: " .$this->refreshRate . "<br> <br>";
}
}
The code above defines three different products with additional properties and methods by extend
ing the Product
class. The extends
keyword is used to extend the Product
class, also known as the parent
class in this case.
Note: The
Laptop
class overrode theProduct
class'addToCart
function by defining anotheraddToCart
function of its own.
You can now use the classes like this:
$tv = new TV('LG TV', 1000, 'A TV', 'image.jpg', '55"', '4K', '60Hz');
echo $tv->formatTVSpecs();
echo $tv->addToCart();
$phone = new Phone('iPhone 12', 1000, 'A phone', 'image.jpg', 'iOS', 8, 256);
echo $phone->formatPhoneSpecs();
echo $phone->addToCart();
$laptop = new Laptop('Macbook Pro', 1000, 'A laptop', 'image.jpg', '5', 16, 512);
echo $laptop->formatLaptopSpecs();
echo $laptop->addToCart();
The code above defines one instance of the classes that extends the Product
class and will return the following result:
Note: A class that extends another class is called a child class, while a class that is being extended is called a parent class.
Benefits of inheritance
Inheritance allows you to reuse code by creating new classes that inherit the attributes and methods of existing classes. This can save a lot of time since you don't have to write the same code repeatedly. It can make code easier to maintain because if a bug is found in the parent class, it only needs to be fixed once, and all the child classes will automatically inherit the fix.
Inheritance creates a hierarchical class structure, making the code easier to understand and organize. You can use the parent-child relationship to group classes into logical categories, making navigating and maintaining the codebase easier. Finally, it enables you to add new features or functionality to an application without modifying the existing code.
Static members
PHP allows you to define properties and methods bound to the class and not instances using the static
keyword. We'll explore how to do that in this section.
Static properties
Static properties are only available to use on the class itself and not the instances. For example, if you want to keep track of how many times the User
class has been used, you can do so like this:
class User {
public $name;
public $email;
public $password;
function __construct($name, $email, $password) {
$this->name = $name;
$this->email = $email;
$this->password = $password;
}
static $usersCount = 0;
}
The code above defines a static
property, usersCount
, inside the User
class. You can now access the property by prefixing it with the self::
syntax:
$user = new User('Abolade William', 'willabolade@ml.com', 'password');
echo User::$usersCount; // 0
The code above will return the value of usersCount
, 0
.
Note: You must add the
$
to the property.
Let's take a look at static methods next.
Static methods
If you want to update the usersCount
every time an instance of User
is created, you can use the static
method:
class User {
// same as above...
static function updateUsersCount(){
self::$usersCount++;
return self::$usersCount . " users registered";
}
}
The code above defines an updateUsersCount
method that updates the usersCount
property. You can now call the updateUsersCount
function on the class each time an instance of the User
class is created:
$user = new User('Abolade William', 'willabolade@ml.com', 'password');
echo User::updateUsersCount(); // 1 users registered
echo User::$usersCount; // 0
Note: You can also access static members inside the class with the class name instead of
self::
like so:User::$usersCount
.
Abstract classes and methods
PHP allows you to define classes with functions that are not defined yet but forces classes that extend them to define their implementation. Abstract classes and methods are created by prefixing the class and method names with the abstract
keyword.
For example, if you want to force every child class that extends the Product
class to implement a formatSpec
function, you can do so with an abstract class:
abstract class Product {
public $name;
public $price;
public $desc;
public $image;
function __construct($name, $price, $desc, $image) {
$this->name = $name;
$this->price = $price;
$this->desc = $desc;
$this->image = $image;
}
public function addToCart(){
return $this->name . " has been added to cart <br> <br>";
}
abstract function formatSpec();
}
The code above defines an abstract Product
class with an abstract formatSpec
method. You cannot create an object based on an abstract class. You need to create classes that extend it.
Note: An abstract class must have at least one abstract method.
You can now create a child class that extends the abstract class:
class Laptop extends Product {
public $cpu;
public $ram;
public $storage;
function __construct($name, $price, $desc, $image, $cpu, $ram, $storage) {
parent::__construct($name, $price, $desc, $image);
$this->cpu = $cpu;
$this->ram = $ram;
$this->storage = $storage;
}
public function formatSpec(){
return $this->name . "<br>" . "i" . $this->cpu . " Processor <br>" . $this->ram . "GB RAM <br>" . $this->storage . "GB SSD <br> <br>";
}
}
The code above defines a Laptop
class that extends the Product
class and implements the formatSpec
function inside it.
Note: You will get an error if you don't implement the abstract methods inside the classes that extend abstract classes.
Interfaces
PHP takes abstraction to the next level by allowing you to define functions that classes must implement inside an interface. An interface is similar to an abstract class but can only have public functions and cannot contain properties and defined methods. Here's an example of an interface:
interface ProductInterface {
public function addToCart();
public function formatSpec();
}
The code above defines a ProductInterface
with two methods that the child class has to implement. A child class that implements the ProductInterface
will look like this:
class Phone implements ProductInterface {
public $name;
public $price;
public $desc;
public $image;
public $os;
public $ram;
public $storage;
function __construct($name, $price, $desc, $image, $os, $ram, $storage) {
$this->name = $name;
$this->price = $price;
$this->desc = $desc;
$this->image = $image;
$this->os = $os;
$this->ram = $ram;
$this->storage = $storage;
}
public function addToCart(){
return $this->name . " has been added to cart <br> <br>";
}
public function formatSpec(){
return $this->name . "<br>" . $this->os . "<br>" . $this->ram . "GB RAM <br>" . $this->storage . "GB <br> <br>";
}
}
The code above defines a Phone
class based on the ProductInterface
using the implements
keyword.
Note: The child class must implement all the methods inside the interface that it implements, or the code will throw an error.
Polymorphism
The word polymorphism originated from two Greek words, poly, which means different or many, and morph, which means form or shape. Polymorphism is a fundamental concept in OOP that allows objects of different classes to be used interchangeably while retaining their unique behavior. It enables you to write more flexible, modular, and easier-to-maintain code.
Polymorphism in PHP is achieved by using abstract classes or interfaces to write code that can be easily extended and modified without modifying the existing code. It also allows you to write more generic code that can work with objects of different classes rather than writing separate code for each class. This reduces code duplication and increases code reusability, making your code more efficient and maintainable.
Traits
PHP allows you to define and use functions that don't fit in a class with traits. A trait is a collection of functions that can be used inside classes without inheriting, extending, or implementing a class or interface.
For example, you can define a trait that contains an addBrandLogo
function, which can be used in all other classes to add a brand logo to product images:
trait AllProductsFunctions {
public function addBrandLogo(){
return "Brand logo added";
}
}
The code above defines a trait (AllProductsFunctions
) with a method (addBrandLogo
) inside it. This trait can now be used inside other classes using the use
keyword:
class Phone implements ProductInterface {
// same as before...
use AllProductsFunctions;
// same as before...
}
The function inside the AllProductsFunctions
trait can now be used on all objects based on the Phone
class. You can use multiple traits in a class by separating the traits' names with a comma.
Note: You can override a trait method by defining a method with the same name inside the class, and a trait method with the same name will override the method that the class inherited.
Benefits of object-oriented programming
Now that you have learned all the basics and advanced concepts you need to know to begin object-oriented programming in PHP and how it helps you to design and create scalable, maintainable, and reusable applications, let's explore some of the significant benefits of OOP in the following sections.
Code reusability
One of the primary benefits of OOP in PHP is code reusability. This means that you can reuse code blocks and functions throughout applications without having to rewrite the entire code from scratch. With OOP, you can create objects that encapsulate a specific set of functionalities and reuse these objects across multiple applications or even within the same application. This helps to reduce the development time and effort required to create complex applications while improving the overall quality of the code.
Scalability
OOP in PHP also makes it easier to scale applications as they grow. By using objects to encapsulate different parts of the application, you can modify or add new functionalities without affecting other parts of the codebase. This makes it easier to maintain and update applications while reducing the risk of introducing bugs or errors. Additionally, OOP makes it easier to modularize code, allowing multiple developers to work on specific parts of the application without needing to understand the entire codebase.
Encapsulation
Encapsulation is a crucial principle of OOP in PHP that helps improve an application’s security and maintainability. With encapsulation, you can hide the internal workings of an object from the rest of the application. This means that the object can only be accessed through its public interface, which helps to prevent unauthorized access to critical parts of the application. Encapsulation also makes it easier to modify or update the internal workings of an object without affecting other areas of the codebase.
Inheritance
Inheritance is another important concept in OOP that allows developers to create new classes based on existing classes. With inheritance, you can inherit the properties and methods of a parent class and then modify or extend them to create new functionality. This makes reusing code easier, reduces redundancy, and creates more efficient applications. Additionally, inheritance helps to promote consistency across different parts of an application, which makes it easier to maintain and update the codebase.
Testability
Finally, OOP in PHP makes it easier to test and debug applications. By encapsulating code into objects, you can isolate specific parts of the application and test them in isolation from other areas of the codebase. This helps to identify bugs and errors more quickly and makes it easier to fix them without affecting the rest of the application. Additionally, OOP makes it easier to write automated tests that can be used to test the application at scale, which helps to improve the overall quality of the code.
Using OOP in PHP offers a range of benefits that can help you create more scalable, maintainable, and reusable applications. As such, OOP has become a popular programming technique for building modern web applications and will likely remain a vital part of the developer toolkit for years.
Conclusion
And that's it! I hope this article achieved its aim of teaching you object-oriented programming in PHP. You learned about classes in PHP, including class properties, class methods, chaining class methods in PHP, common class constants in PHP, and class inheritance. We also explored how to use static members, abstract classes and methods, interfaces, polymorphism, and traits.
Finally, you learned some of the significant benefits of object-oriented programming in PHP.
Posted on April 1, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.