Object oriented programming (OOP) is a programming paradigm with objects and classes. Objects are usually instances of classes which have methods (functions defined inside a class) and properties (variables defined in class as descriptions of that class).
PHP has always been an object oriented programming language. PHP 5 introduced a full object model. As newer versions emerged over time, PHP reached the point of being almost a fully object oriented language. Many still consider PHP object oriented capabilities as not fully object oriented, but it’s a matter of a perspective and coding style as well.
Many developers don’t find the concept of the object oriented paradigm to be useful, because it seems scary, or because they don’t yet understand the practical benefits of it, but for more advanced scripts, OOP is essential part of PHP development.
Before we get into details, let’s define some important OOP terms.
Class: This is a programmer-defined datatype, which includes local functions and local data. You can think of a class as a template for making many instances of the same kind (or class) of object.
Object: An individual instance of the data structure defined by a class. You define a class once and then make many objects that belong to it. Objects are also known as instances.
Member variable: These are the variables defined inside a class. This data will be invisible to the outside of the class and can be accessed via member functions. These variables are called attributes of the object once it’s created.
Member function: These are the functions defined inside a class and are used to access object data.
Inheritance: When a class is defined by inheriting existing function of a parent class, it is called inheritance. Here, a child class inherits some or all member functions and variables of its parent class.
Parent class: A class that is inherited from by another class, also referred to as a base class or super class.
Child class: A class inherits from another class (the parent class), also referred to as a subclass or derived class.
Polymorphism: This is an object oriented concept where the same function can be used for different purposes. For example, the name of a function remaining the same but taking a different number of arguments and performing a different task.
Overloading: A type of polymorphism in which some or all operators have different implementations depending on the types of their arguments. Similarly, functions can also be overloaded with different implementations.
Data abstraction: Any representation of data in which the implementation details are hidden (abstracted).
Encapsulation: Refers to a concept whereby data is encapsulated together with member functions to form an object.
Constructor: Refers to a special type of function to be called automatically whenever an object is formed from a class.
Destructor: Refers to a special type of function to be called automatically whenever an object is deleted or goes out of scope.
General form for defining a new class in PHP:
<?php
class PhpClass
{
public $var1;
public $var2 = 'string value';
public function myfunction($arg1, $arg2)
{
// ...
}
// ...
}
Explanations of keywords used in the above class definition:
class
, followed by the name of the class, PhpClass
.{}
, which include any number of properties and
methods.public
, which is then
followed by a conventional $variableName. It may also have an initial
assignment of values.Here is an example which defines a class Book
:
<?php
class Book
{
public $price;
public $title;
public function setPrice($price)
{
$this->price = $price;
}
public function getPrice()
{
return $this->price;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
}
Special variable $this
refers to the current object (i.e. itself).
Once you define your class, you can create as many objects as you like of that
class type. With the new
keyword, you create an object (a class instance):
$physics = new Book();
$maths = new Book();
$chemistry = new Book();
Here we have created three new objects which are independent of each other.
Let’s check how to call methods and process class properties. After creating your objects, you will be able to call class methods related to that object. One class method will be able to process class properties of the related object only.
The following example shows how to set titles and prices for these three books by calling class methods.
$physics->setTitle('Physics for High School');
$physics->setPrice(10);
$maths->setTitle('Algebra');
$maths->setPrice(7);
$chemistry->setTitle('Advanced Chemistry');
$chemistry->setPrice(15);
Now you call another methods to get the values from above example:
echo $physics->getTitle();
echo $physics->getPrice();
echo $maths->getTitle();
echo $maths->getPrice();
echo $chemistry->getTitle();
echo $chemistry->getPrice();
This will produce the following result:
Physics for High School
10
Algebra
7
Advanced Chemistry
15
Constructor method __construct()
is a special type of method which is called
automatically whenever an object is created.
Constructor methods accept as many arguments as you define in the class definition.
The following example will create one constructor for Books
class and it will
initialize the price and title for the book at the time of object creation.
public function __construct($title, $price)
{
$this->price = $price;
$this->title = $title;
}
With the above __construct()
we don’t need to call set methods separately to
set the price and title. We can initialize these two member variables at the
time of object creation only:
$physics = new Book('Physics for High School', 10);
$maths = new Book('Advanced Chemistry', 15);
$chemistry = new Book('Algebra', 7);
/* Get those set values */
echo $physics->getTitle();
echo $physics->getPrice();
echo $maths->getTitle();
echo $maths->getPrice();
echo $chemistry->getTitle();
echo $chemistry->getPrice();
The above will produce the same result as in the previous example.
Like with the constructor method, you can also define a destructor by using the
special method __destruct()
. A destructor is called automatically as soon as
there are no more references to a particular object or during the shutdown
sequence. Within a destructor you can release all resources.
From the Books
class example above, let’s add the following destructor.
public function __destruct()
{
echo "A book ({$this->title}) is destroyed.\n";
}
$physics = new Book('Physics for High School', 10);
$maths = new Book('Advanced Chemistry', 15);
$chemistry = new Book('Algebra', 7);
$mathsCopy = $maths;
unset($physics, $maths, $chemistry);
echo "Program is about to exit.\n";
A book (Physics for High School) is destroyed.
A book (Algebra) is destroyed.
Program is about to exit.
A book (Advanced Chemistry) is destroyed.
You can see that Advanced Chemistry
was shown after the text
Program is about to exit.
, even though $maths
was previously unset. That
was because there was still another reference to the object ($mathsCopy
).
PHP class definitions can optionally inherit from a parent class definition by
using the extends
keyword:
class Child extends Parent
{
// Definition body
}
The effect of inheritance is that the child class (or subclass, or derived class) has the following characteristics:
The following example inherits the Book
class and adds additional
functionality compared to the parent class.
class Novel extends Book
{
public $publisher;
public function setPublisher($publisher)
{
$this->publisher = $publisher;
}
public function getPublisher()
{
return $this->publisher;
}
}
Class Novel
adds two additional methods to the parent class.
Methods defined in child classes override methods with the same name in parent classes. In a child class, we can modify the definition of a method inherited from parent class.
In the following example, the getPrice()
method is overriden to return a
price number with currency.
public function getPrice()
{
return $this->price . " EUR";
}
Unless you specify otherwise, properties and methods of a class are public by default. This means that they may be accessed in three possible situations:
Until now, we have seen all members as public members. If you wish to limit the accessibility of the members of a class, you define class members as private or protected.
By setting a member as private, you limit its accessibility to only the class where it is defined. The private member can not be used in inherited classes nor outside the class.
A class member can be made private by using the private
keyword in front of
the member.
class Car
{
private $model = 'skoda';
$driver = 'SRK';
public function __construct()
{
// Statements here run every time
// an instance of the class
// is created.
}
public function myPublicFunction()
{
return("I'm visible!");
}
private function myPrivateFunction()
{
return("I'm not visible outside!");
}
}
When the class Car
is inherited by another class with the extends
keyword,
the method myPublicFunction()
and the property $driver
will be visible. The
extended class will not have any awareness of nor access to
myPrivateFunction()
or $model
, because they are declared as private.
A protected property or method is accessible in the class in which it is
declared and in inherited classes. Protected members are not available outside
of those two contexts. A class member can be made protected by using the
protected
keyword in front of the member.
Here is a different version of the class Car
:
class Car
{
protected $car = 'skoda';
$driver = 'SRK';
public function __construct()
{
// Statements here run every time
// an instance of the class
// is created.
}
public function myPublicFunction()
{
return("I'm visible!");
}
protected function myPrivateFunction()
{
return("I'm visible in child class!");
}
}
Interfaces provide common method names to implementors. Different implementors can implement those interfaces according to their requirements. You could say that interfaces are skeletons which are implemented by developers.
Let’s define an interface:
interface Mail
{
public function sendMail();
}
The class then implements the above interface like this:
class Report implements Mail
{
public function sendMail()
{
// Code that sends an email.
}
}
A class constant is an immutable value. Once you declare a constant, it can not be changed:
class MyClass
{
const MARGIN = 1.7;
public function __construct($argument)
{
// Statements here run every time
// an instance of the class
// is created.
}
}
In this class, MARGIN
is a constant. It is declared with the keyword const
and it can not be changed under any circumstances to anything other than the
default value 1.7
. Unlike variable names, constant names doesn’t have a
leading $
.
Declaring class members or methods as static makes them accessible without the need for class instantiation. A member declared as static can not be accessed with an instantiated class object (although a static method can).
Try out the following example:
class Foo
{
public static $myStatic = 'foo';
public function staticValue()
{
return self::$myStatic;
}
}
print Foo::$myStatic . "\n";
$foo = new Foo();
print $foo->staticValue() . "\n";
The final
keyword prevents child classes from overriding a method by adding
final
to the definition. If the class itself is being defined final then it
can not be extended.
The following example results in “Fatal error: can not override final method BaseClass::moreTesting()”
class BaseClass
{
public function test()
{
echo "BaseClass::test() called<br>";
}
final public function moreTesting()
{
echo "BaseClass::moreTesting() called<br>";
}
}
class ChildClass extends BaseClass
{
public function moreTesting()
{
echo "ChildClass::moreTesting() called<br>";
}
}
Instead of writing a new constructor for the subclass, you can call the parent’s constructor explicitly and then do whatever is necessary in addition for instantiation of the subclass. Here’s a simple example:
class Person
{
private $firstName;
private $lastName;
public function __construct($firstName, $lastName)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
}
public function getFullName()
{
return $this->firstName.' '.$this->lastName;
}
}
class Student extends Person
{
private $title;
public function __construct($title, $firstName, $lastName)
{
parent::__construct($firstName, $lastName);
$this->title = $title;
}
public function getFullName()
{
return $this->title.' '.parent::getFullName();
}
}
In this example, we have a parent class Person
, which has a constructor with
two arguments, and a subclass Student
, which has a constructor with three
arguments. The constructor of Student
calls the parent constructor with
parent::__construct()
and then sets an additional field. Class Student
also
overrides the getFullName()
method.