This is a quick tutorial on object-oriented programming (OOP) in PHP. There are two parts to this tutorial.
Target Audience: Developers who know procedural PHP but want to quickly learn about OOP in PHP.
Table of Contents
Class
A class is just a definition of an object. Every class definition begins with the keyword class followed by the class name. Then you have curly braces that surround the class definition. Here I am defining a student class and making use of two built-in methods:
- get_declared_classes shows list of declared classes
- class_exists checks if a class exist
<?php class Student { //class definition } // prints a list of defined classes $declaredClasses = get_declared_classes(); echo "declared classes are ". implode ("<br>", $declaredClasses); // checks if a class exists if(class_exists('Student')) echo "class exists"; else echo "nop"; ?>
Instance
In general use, an instance is a single occurrence of something. When we’re talking about object-oriented programming, that single occurrence of something is a single instance created from a class definition. Instance and object are used interchangeably but technically instance is the correct term. An instance is created using new keyword followed by class name. It is also called instantiation. We will be making use of a built-in method for instances:
- get_class gets the class name from instance
<?php class Student { // class definition } // creating two instances $student1 = new Student; $student2 = new Student; // Get class name of instance echo get_class($student2); ?>
Class Properties
Class properties are variables that hold instance values. Class properties are also called class attributes or instance attributes. Below we are setting class properties inside class definition and referring it through an instance. We will be using three built-in functions as well:
- get_class_vars gets class properties
- get_object_vars gets instance properties
- property_exists checks property existence in a class
<?php class Student { // class definition // class properties - we put 'var' before them var $name; var $age; var $school = "DPS"; var $country = "NONE"; } $student1 = new Student; // class instance $student1->name = "Hafiz";// referring class property with instance echo $student1->name." studied at ".$student1->school."."; echo "<pre>".print_r(get_class_vars('Student'))."</pre>"; // list of class properties echo "<pre>".print_r(get_object_vars($student1))."</pre>"; // list of class instance properties if(property_exists($student1, 'age')) // class property exists through instance echo "class property exists."; else echo "class property does not exist."; ?>
Class Methods
When we define a function inside a class definition it is called a class method. Some people call it class function but the class method is a more appropriate term. We will make use of two functions here:
- get_class_methods gets class methods
- method_exists checks method existence in a class definition
<?php class Student { // class definition // class properties var $name; var $age; var $school = "DPS"; var $country = "NONE"; function showText(){ // class method return "hello I am working from class definition"; } } $student1 = new Student; // class instance $student1->name = "Hafiz"; echo $student1->name." studied at ".$student1->school; // Output: Hafiz studied at DPS echo $student1->showText(); // calling class method // Output: hello I am working from class definition echo "<pre>".print_r(get_class_methods('Student'))."</pre>";; // Show class methods if(method_exists('Student', 'show')) // method in class definition echo "Method exists"; else echo "Method does not exists"; ?>
Refer an instance
Refer an instance means when we call a class method it must refer to the “instance properties” instead of “class properties”.
- $this-> used inside the class to refer the instance properties only. This means if there are several instances each one will have its separate instance properties.
- $variable_name-> used outside class to refer to object properties
<?php class Student { // class definition // class properties var $name; var $age; var $school = "DPS"; var $country = "NONE"; function fullName(){ // class method // referring class properties of instance from class method return " ".$this->name." is ".$this->age; } } $student1 = new Student; // class instance $student1->name = "Hafiz"; $student1->age = 29; echo $student1->name." studied at ".$student1->school; // Output: Hafiz studied at DPS echo $student1->fullName(); // instance calling class method // Output: Hafiz is 29 echo "<pre>".print_r( get_object_vars ($student1))."</pre>";; // list instance properties ?>
Inheritance & Subclass
When a new class takes on properties and methods of an existing class, is called class inheritance or simply inheritance. The class which inherits from a parent class is also called a subclass. Inheritance prevents code repetition by organizing code. We are defining three classes i.e User, dealer, consultant.
The user is the parent class. Dealer is inheriting everything from User class and then the consultant is inheriting everything from dealer class. So the hierarchy becomes, the dealer is a subclass of user and consultant is a subclass of the dealer.
We will be making use of the following functions:
- get_parent_class() gets the name of parent class from class instance.
- class_parents() shows a list of parent classes
- is_subclass_of() checks if the class of current instance is a subclass of a parent class
<?php class user { // class definition var $name; // class property var $location; // class property function createSentence () { // class method // referring class properties of instance from class method return "The user ".$this->name." is from ".$this->location." and phone is".$this->phone."<br>"; } } class dealer extends user { // subclass of user - inheriting var $phone; // class property } class consultant extends dealer { // subclasss of dealer - inheriting function createSentence () { // class method // referring class properties of instance from class method return "<br>The user ".$this->name." phone is ".$this->phone; } } $u = new user; // class instance $u->name = 'Hafiz'; $u->location = 'Pakistan'; echo $u->createSentence(); // Notice: Undefined property: user::$phone // Output: The user Hafiz is from Pakistan and phone is $d = new dealer; // class instance $d->name = 'Haseeb'; $d->location = 'India'; $d->phone = '12345678'; echo $d->createSentence(); // Output: The user Haseeb is from India and phone is12345678 $c = new consultant; // class instance $c->name = "Faraz"; $c->phone = "111222333"; echo $c->createSentence(); // Output: The user Faraz phone is 111222333 print_r(get_parent_class($c)); // parent class from instance // Output: dealer echo "<pre>".print_r(class_parents($c))."</pre>"; // list parent classes from instance echo is_subclass_of($c, 'User'); // Check if its a subclass // Output: 1 ?>
Visibility Modifiers
Visibility modifiers are used to control access to objects, properties, and methods. There are three visibility modifiers.
- Public accessible from anywhere
- Protected accessible from class and subclasses
- Private accessible from the class only
Let’s see how to use them:
<?php class Student { // class definition // class properties public $name; // accessible outside class public $age; // accessible outside class public $school = "DPS"; // accessible outside class private $country = "Pakistan"; // inaccessible outside class // protected class method - accessible from subclass protected function showText($name){ // calling private method return "<br>hello I am <b>{$this->showName($name)}</b>"; } // private class method - accessible from own class only private function showName($name) { // private class method return $this->name." Sir"; } } class parttimeStudent extends Student { // subclass of Student function callProtected($name) { // public class method return $this->showText($name); // calling protected method } } $student1 = new parttimeStudent; // class instance $student1->name = "Hafiz"; echo $student1->callProtected('asdfadf'); // calling public method ?>
Overriding
When subclass redeclares class properties or class method in its definition which are previously defined in the parent class, this redeclaration is called overriding. For example, if there is class of “Citizen” we can extend its properties age, occupation and education to another class called “SeniorCitizen”. This way we can add more properties to class “SeniorCitizen” without effecting the citizen class. This redeclaration of any property or method of parent class inside the “SeniorCitizen” class will be called overriding.
<?php class citizen { var $age = 1; var $occupation; var $education; function do_something() { echo "I am a citizen"; } } // extending properties and methods to seniorCitizen class SeniorCitizen extends citizen { var $retired = true; // Overriding function do_something() { echo "I am a senior citizen and my age is $this->age"; } } $user = new SeniorCitizen; // Inheriting class property 'age' from citizen class $user->age = 42; $user->do_something(); /* output: I am a senior citizen and my age is 42 */ ?>
Overloading
Overloading is a feature of PHP that handles calls to properties and methods which do not exist or are not visible. So here’s an example:
<?php class member { // no class property exists in class } $person = new member; echo $person->name; // undefined property because property do not exist $person->name = "faraz"; // overloading, we explicitly defined it echo $person->name; // faraz ?>
Setter and getter methods
So far we have been interacting with class properties directly. A good practice is to access class properties through setter method and read through a getter method. This is how it is done:
<?php class Student { private $name; // setter - setting private property value public function setter_method($value) { $this->name = $value; } // getter - processing private property value public function getter_method() { echo $this->name; return $this->name; } } $std = new Student; $std->setter_method("John"); $std->getter_method(); ?>
Static Modifiers
Static modifiers are properties and methods which we can access inside and outside class without creating an instance. In order to define them, we’re going to use the keyword static. So for example, if I have a “user” class, I can have a static property for grades by putting the static keyword in front of it.
Important: Inherited static properties are shared values. That means its value can be changed from anywhere.
Here is a simple example:
<?php class user { private static $client = 0; // static inside class public static $lead = 0; // static outside class private static function add_client () { // accessing static property inside class using self:: return self::$client += 1; } private static function add_lead () { // accessing static property inside class using self:: return self::$lead += 1; } public static function is_admin ($action) { switch($action) { case 'add_client': return self::add_client(); break; case 'add_lead': return self::add_lead(); break; } } } //calling static method from class $clients = user::is_admin("add_client"); $clients = user::is_admin("add_client"); $lead = user::is_admin("add_lead"); echo "Total clients are ".$clients."<br>"; echo "Total leads are ".$lead."<br>"; echo "Directly accessing number of leads ". user::$lead; /* output: Total clients are 2 Total leads are 1 Directly accessing number of leads 1 */ ?>
Class constants
The class constant is the opposite of static modifiers. That is their value remains constant and cannot be changed.
In this example, I am defining a class constant called “paymentReminder” that sets a 60 minutes reminder to make payment from the time you place an order. Here is the code:
<?php class user { public const paymentReminder = 60*60; public static function invoiceGenerated () { // Takes current time and adds 60 minutes through class constant. return time() + self::paymentReminder;; } } $reminderSent = user::invoiceGenerated(); echo "current time is " .gmdate('H:m',time()) ." reminder will be sent in one hour at " .gmdate('H:m', $reminderSent); /* Output: current time is 16:01 reminder will be sent in one hour at 17:01 NOTE: your output will differ due to time */ ?>
Referring parent class
When referring parent class from the subclass, we have two options:
- Use class name to refer e.g user::paymentReminder (as we did above)
- Refer parent class using ‘parent’ keyword e.g parent::paymentReminder (considered best practice)
In the example below, I am accessing static class property $resizing_enabled setting its value false. Using simple if/else statement referring parent class method.
<?php class image { public static $resizing_enabled = true; protected static function resize_image() { echo '800 x 600'; } } class thumbnail extends image { public static function resize_image() { if(self::$resizing_enabled) { echo '100 x 100'; } else { // referring parent class method parent::resize_image(); } } } image::$resizing_enabled = false; thumbnail::resize_image(); ?>
Late Static Binding
At this point, we know that the “self” keyword is used to reference the called class properties or methods. Before explaining late static binding, let’s see a problem with “self”.
Problem: Static references to the current class like self:: are resolved using the class in which the function belongs, as in where it was defined, neglecting referred class defintions.
<?php class user { protected static $name = "ABC"; public static function showName () { echo self::$name; } } class dev extends user { protected static $name = "XYZ"; } user::showName(); dev::showName(); /* Output ---------- user : ABC dev : ABC ---------- this is the problem you see "self" limitation? XYZ is being ignored in dev class definition */ ?>
Solution: Swap “self” with “Static”.
“Static::” references the class that was initially called at runtime and hence shows result from there.
class user { protected static $name = "ABC"; public static function showName () { echo "<br>".get_called_class() ." : "; echo static::$name; } } class dev extends user { protected static $name = "XYZ"; } user::showName(); dev::showName(); /* Output ---------- user : ABC dev : XYZ ---------- Now fine, dev name is now XYZ, this is late static binding*/ ?>