PHP: OOPs, Classes and Objects

Support for object-oriented programming (OOP) was introduced in PHP 3 and improved in PHP 4. Programmers with C++/Java background will be familiar with common object-oriented programming terms and concepts like object, class, data encapsulation, constructor, destructor, inheritance, method overriding, method overloading, interface, polymorphism, etc.

Here, we will learn about them in the perspective of PHP as we go along, irrespective of your programming background.

Objects & Classes

Consider a real-world object, an orange fruit. An orange has certain distinct properties like taste, peel colour, weight, etc. We can define PHP variables like $taste, $colour, $weight to hold the values of these properties. With these properties and their values in hand (data), we can write PHP functions to do something with them, like setting/getting the hex code of peel colour, converting its weight to pounds or simply fetching its name. So far, like in functional programming, these data and functions are separate entities for us. In OOP, there is a way to group these variables and related functions together, constituting an entity known as object. An object is a bundled-entity of data (variables) and related code (functions or methods). The variables and functions inside an object are known as properties and methods respectively.

php classes and objects The above strawberry, orange and raspberry icons are by Smashicons from https://www.flaticon.com

Simlarly, we can go about creating separate objects consisting of the same properties and functions for strawberry, mango, pineapple, guava, pear, banana, etc. — each with distinct property values. But there is a better way to do it. We can pick common instance properties like $name, $colour and instance methods and construct a common template for creating them all. After all, they are all fruits. Such a template is known as a class. So, a class is a template for an object.

Now we go about creating a class. Creating a class in PHP in quite simple. It begins with the keyword class, followed by its name, followed by a pair of opening and closing braces. All its properties and methods goes inside the braces. Below we declare a simple class called Fruit consisting of one property $name and two methods setName() and getName() for setting and getting/fecthing the $nameproperty.

					
					<?php 
						class Fruit {
							/* properties */
							private $name;

							/* methods */
							function setName($n) {
								$this->name = $n;
							}

							function getName() {
								return $this->name;
							}
						}
					?>
					
				

You might have noticed the private keyword infront of the $name property. It is one of the three access restriction keywords in PHP and it simply means that only methods inside the class can access it. You will come across it in detail later. Also note the use of $this variable, which denotes a reference to the object itself. Using $this along with -> gives you the provision to reference the object's properties and methods.

Now that we have declared a class, we can create an instance of it, popularly known as object. An instance of a class is created using the new keyword. In the example below, $orange is an instance of the class Fruit.

					
					<?php 
						class Fruit {
							/* properties */
							private $name;

							/* methods */
							function setName($n) {
								$this->name = $n;
							}

							function getName() {
								return $this->name;
							}
						}

						$orange = new Fruit();
						$orange->setName('Orange');
						echo $orange->getName();
					?>
					
				

Similarly, we create another object called $raspberry.

					
					<?php 
						$raspberry = new Fruit();
						$raspberry->setName('Raspberry');
						echo $raspberry->getName();
					?>
					
				

You can use the instanceof operator to check if an object belongs to a particular class.

					
					<?php 
						$raspberry = new Fruit();
						var_dump($raspberry instanceof Fruit);
					?>
					
				

Constructors & Destructors

Now we need not always keep a separate function to set/assign some value to a property. Which means, we can do away with the setName() method above. There is a special method called __construct() which can be used for the initialization purpose. This method is called automatically upon creation of an object by the new keyword. We can rewrite our above Fruit class without the setName() method now, the property $name is initialized by passing the value as an argument inside the parentheses after the class name.

NOTE: There is a double underscore __ before construct().

					
						<?php 
							class Fruit {
								private $name;

								function __construct($n) {
									$this->name = $n;
								}

								function getName() {
									return $this->name;
								}
							}

							$orange = new Fruit('Orange');
							echo $orange->getName();
						?>
					
				

Now there is a method called _destruct() which does the opposite of _construct(). They are called when you want to destroy all references to an existing object.

					
						<?php 
							class TheDestroyer {
								function __destruct() {
									echo 'An object is being destroyed';
								}
							}

							$orange = new TheDestroyer();
							$orange = NULL;
						?>
					
				

Object Inheritance: Subclasses

In PHP, there is a provision to create a class which inherits all of the non-private properties and methods of an existing class, while having some extra of its own. Such a class is known as a subclass or a derived class and the concept of a creating a new class reusing the properties and methods from an existing class is known as inheritance.

php subclasses

Consider the class below:

					
						<?php 
							class Perfume {
								private $name;
					
								function __construct($n) {
									$this->name = $n;									
								}

								function getName() {
									return $this->name;
								}

								function getBrand() {
									return 'Chanel';
								}
							}					
						?>
					
				

If we create an instance of Perfume and invoke the getBrand() method, it will return "Chanel".

					
						<?php						
							$chanel = new Perfume("No. 5");
							echo $chanel->getBrand() . PHP_EOL;
						?>
					
				

Now suppose we want to create another perfume object belonging to a different brand, say, Hermes. If we create it as an instance of the Perfume class, invoking the the getBrand() method will return its brand as "Chanel", which it is not. Can we modify the getBrand() method to return "Hermes" instead? This is where subclasses come in and they allow you to override non-private methods inherited from their respective parent classes.

A subclass is created using the extends keyword on its parent class. Below we show an example by creating one called Hermes, by extending the class Perfume. The method getBrand() in defined again in the derived class by modifying it to return "Hermes" instead of "Chanel". This is method overriding.

					
						<?php 
							class Perfume {
								private $name;
					
								function __construct($n) {
									$this->name = $n;									
								}

								function getName() {
									return $this->name;
								}

								function getBrand() {
									return 'Chanel';
								}
							}

							class Hermes extends Perfume {
								function getBrand() {
									return 'Hermes';
								}
							}		
						?>
					
				

Now if we create an instance of the Hermes class and invoke the getName() method, it will return "Hermes" instead of "Chanel".

					
						<?php 
							class Perfume {
								private $name;
					
								function __construct($n) {
									$this->name = $n;									
								}

								function getName() {
									return $this->name;
								}

								function getBrand() {
									return 'Chanel';
								}
							}

							class Hermes extends Perfume {
								function getBrand() {
									return 'Hermes';
								}
							}						

							$hermes = new Hermes("Terre d'Hermes");
							echo $hermes->getName() . PHP_EOL;
							echo $hermes->getBrand() . PHP_EOL;
						?>
					
				

Going further, you might have wondered if we can prevent a class's method from getting modified in the child classes? Yes we can. You just need to add the keyword final before the method definition.

					
						<?php 
							class Perfume {
								private $name;
					
								function __construct($n) {
									$this->name = $n;									
								}

								function getName() {
									return $this->name;
								}

								final function getBrand() {
									return 'Chanel';
								}
							}
						?>
					
				

Now if you try to override the getBrand() method inside one of the child classes, it will throw the following error in the browser:

					
						Fatal error: Cannot override final method Perfume::getBrand() 
					
				

Visibilty in PHP: public, protected and private Properties

PHP 5 introduced the three access restriction keywords for members of a class: public, protected and private. Before that, in PHP 3 and 4, class properties were declared with the var keyword, which is the same as public in PHP 5.

php visibility keywords Girl icon by Freepik from https://www.flaticon.com

NOTE: In PHP 3 and 4, class members were defined with the var keyword.

There was a PHP RFC (Request for Comments) to deprecate code var in PHP 7. However, the status stands "declined" as of now; var will remain a reserved word in PHP 8.0.

Below, we go through each of the access modifiers one by one:

  • public Public properties can be accessed from within a class's method and from methods belonging to the class's derived classes via the $this variable. They can also be accessed from outside the class through an instance of it or through an instance of any of its derived classes.
  • protected Protected properties can be accessed from inside a class's method and from any method belonging to the class's subclass via the $this variable. However, they cannot be accessed from outside the class.
  • private Private properties can be accessed only from within a class's method. Unlike protected properties, they are inacccessible from within the methods of inheriting classes.

We will undertsand them better through few examples given below. We declare a new class called Account containing three properties — $name as public, $email as protected and $password as private. An instance of the Account class is created. The property $name is accessible from outside the class as it is a public property. But $email and $password, being protected and private properties, are not accessible from outside the class:

					
						<?php 
							class Account {
								public $name = "Agnes"; 
								protected $email = "agnes@scriptverse.dev";
								private $password = "bFN5rpx8";
							}

							$agnes = new Account();
							echo $agnes->name . PHP_EOL; // OK. $name is public
							echo $agnes->email . PHP_EOL; // ERROR. $email is protected
							echo $agnes->password; // ERROR. $email is private
						?>
					
				

All public, protected and private properties are accessible inside the class's own methods:

					
						<?php 
							class Account {
								public $name = "Agnes"; 
								protected $email = "agnes@scriptverse.dev";
								private $password = "bFN5rpx8";	

								function getAccount() {
									echo $this->name . PHP_EOL; // OK. $name is public
									echo $this->email . PHP_EOL; // OK. $email is protected
									echo $this->password; // OK. $password is private
								} 					
							}
						?>
					
				

All public and protected properties from a parent class are accessible from a subclass, but not private properties:

					
						<?php 
							class Account {
								public $name = "Agnes"; 
								protected $email = "agnes@scriptverse.dev";
								private $password = "bFN5rpx8";
							}

							class SubAccount extends Account {
								function getAccount() {
									echo $this->name . PHP_EOL; // OK. $name is public
									echo $this->email . PHP_EOL; // OK. $email is protected
									echo $this->password; // ERROR. $password is private
								} 
							}
						?>
					
				

Visibility in PHP: public, protected and private Methods

The rules are the same for the methods as well. And if a method is declared without any any access restriction keyword, it is defined public.

NOTE: Method declared without any explicit visibility keyword means its visibility is public.

  • public A public method can be invoked from outside the class and from within one of the methods inside the class or from within an inheriting class.
  • protected A protected method can be invoked from within one of its class methods or from within an inheriting class. But it cannot be invoked from outside a class.
  • private A private method can be invoked only from within one of its class methods; it cannot be invoked from within an inheriting class.

As with properties, only public methods are accessible from outside the class:

					
						<?php 
							class Account {
								public $name = "Agnes"; 
								protected $email = "agnes@scriptverse.dev";
								private $password = "bFN5rpx8";	

								public function getName() {
									echo $this->name . PHP_EOL;
								} 	

								protected function getEmail() {
									echo $this->email . PHP_EOL;
								}	

								private function getPassword() {
									echo $this->password;
								}			
							}

							$agnes = new Account();
							$agnes->getName(); // OK. getName() is public
							$agnes->getEmail(); // Error. getEmail() is protected
							$agnes->getPassword(); // Error. getPassword() is private
						?>
					
				

Both public and protected methods can be called from within an inheriting class, but not private methods:

					
						<?php 
							class Account {
								public $name = "Agnes"; 
								protected $email = "agnes@scriptverse.dev";
								private $password = "bFN5rpx8";	

								public function getName() {
									echo $this->name . PHP_EOL;
								} 	

								protected function getEmail() {
									echo $this->email . PHP_EOL;
								}	

								private function getPassword() {
									echo $this->password;
								}			
							}

							class SubAccount extends Account {
								function fetchName() {
									return $this->getName(); // OK. getName() is public
								}
								
								function fetchEmail() {
									return $this->getEmail(); // OK. getEmail() is protected
								}

								function fetchPassword() {
									return $this->getPassword(); // ERROR. getPassword() 
																		// is private
								}		
							}

							$agnes = new SubAccount();
							echo $agnes->fetchName();
							echo $agnes->fetchEmail();
						?>
					
				

So far we have covered basic OOP concepts like object, class, constructor, destructor, inheritance and the access specifiers public, protected and private. But more important concepts like polymorphism, abstract methods and classes, interfaces, etc remain to be covered. We proceed on to learn about static properties, static methods, class constants and the use of self:: and parent:: keywords in our next tutorial.