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.
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 $name
property.
<?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.
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.
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.