Understanding object oriented programming
This article is based upon an OOP bootcamp taught by Jeffrey Way from Laracast. It comprises my course notes along with personal code examples.
Terminology
Let's dive into it and create a football player. In object oriented programming terms we use a different terminology: We create an object of the class FootballPlayer
.
class FootballPlayer
{
public $name;
public $position;
public function __constructor($name, $position)
{
$this->name = $name;
$this->position = $position;
}
}
$playerA = new FootballPlayer('Marco Reus', 'Striker');
$playerB = new FootballPLayer('Axel Witsel', 'Midfield');
var_dump($playerA->name); // Marco Reus
var_dump($playerB); // Axel Witsel, Midfield
Classes
What is a class? Refer to a class as a blueprint for an object that defines certain characteristics and behavior. In our example we defined the class FootballPlayer
.
Objects, Instances, and $this
An object is a representation of a defined class. When we talk about a specific object we refer to it as an instance. Referring to our our example, playerA
is an instance of FootballPlayer
. In more technical terms: An instance is an object in memory. It can be addressed with the keyword $this
.
Variables
Variables are containers to store information. From a class perspective variables ar called attributes. In PHP variables always start with the $
sign, are case sensitive and must either start with a letter (A-Z, a-z) or an `_` (underscore).
Methods
A method is a function within a class. It defines certain behavior of a class. A constructor is a special method that is trigged whenever a new object of a class will be initiated.
Scope
Scope refers to the visibility of variables and methods. We differentiate among three different types of visibility:
- public: makes a variable/method available from everywhere, thus also other classes and instances of objects
- protected: makes a variable/method available in the current class and all its sub-classes, including the parent class
- private: makes a variable/method only available within it's own class
Protection and Security
Imagine the following business requirement: The email address of $user
is only available if the profile is set to public. We implement this with the help of a getter function and private variables.
<?php
class User
{
public $name;
private $email;
private $public = false;
public function __construct($name, $email)
{
$this->name = $name;
$this->email = $email;
}
public function makeProfilePublic()
{
$this->public = true;
}
public function getEmail()
{
if ($this->public) {
return $this->email;
}
throw new Exception('Profile is not public');
}
}
$user = new User('Jan', 'info@example.org');
$user->makeProfilePublic();
var_dump($user->getEmail()); // info@example.org
Getters and Setters
If you want to provide more protection and security to your variables you can make use of getters()
and setters()
. In contrast to manipulating or retrieving variables directly, you access those variables through a setter function (for manipulating purpose) or a getter function (for retrieving purpose). Those functions enable you to add additional behavior, e.g. make the $email
only available if $public
is true.
Encapsulation
The term sounds more complicated as it is. The idea behind it is hiding variables and methods that should not be accessed from the public interface.
- protected: protected variables and methods can still be accessed from class extensions
- private: even class extensions have no access to private variables and methods
Inheritance
The example introduces an abstract class called Shape
that defines that every sub-class gets a default color green if no other one is defined. All sub-classes may retrieve the color attribute via getColor()
. Moreover, through the abstract method getArea()
the parent-class Shape
demands that each subclass introduces a behavior to calculate the area of the respective body.
<?php
new abstract Shape
{
protected $color;
public function __constructor($color = 'green')
{
$color = $this->color;
}
public function getColor()
{
return $this-color;
}
abstract protected function getArea();
}
new Square extends Shape
{
protected $length = 5;
public function getArea($length)
{
return pow ($this->length, 2);
}
}
new Triangle extends Shape
{
protected $base = 7;
protected $height = 4;
public function getArea($base, $height)
{
return .5 $this->base * $this->height;
}
}
Override behavior and attributes
If a sub-class should get different attribute values and / or behavior compared to its parent class you may simply override variables and functions within the subclass.
new Shape
{
public $color = 'black';
}
new Circle extends Shape
{
public $color = 'green';
}
Abstract classes
Use an abstract class if you want to introduce common attributes and behavior that should be inhibited by all sub-classes. However, an abstract class can not be instantiated by itself.
$myshape = new Shape; // error because abstract class can not be instantiated
Abstract methods
If you want that each subclass defines it individual behavior for e.g. area calculation, you make use of a template method design pattern.
new Shape
{
abstract protected function getArea();
}
This example illustrates, that each subclass of Shape
needs to define its own getArea()
function.
NOTE: A similar result can be achieved by making use of interfaces. Indeed, from a design pattern perspective there exists the claim: Favor composition over inheritance. Please refer to the resources for further information.
Messages
This is about sending data among objects. Consider the following example. A Club
hires a Player
.
class Club
{
public $name;
protected $team = [];
public function __construct($name)
{
$this->name = $name;
}
public function hire(Player $player)
{
$this->team[] = $player;
}
public function getTeam()
{
return $this->team;
}
}
class Player
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
}
// create a new club
$bvb = new Club('BvB');
// create some players
$sammer = new Player('Matthias Sammer');
$klos = new Player('Stefan Klos');
$ricken = new Player('Lars Ricken');
// club hires player
$bvb->hire($sammer);
$bvb->hire($klos);
$bvb->hire($ricken);
// get team roster of club
var_dump($bvb->getTeam()); // Sammer, Klos, Ricken
Type declaration
Type declaration, also known as type hinting is a security mechanism that proofs whether an argument for a method is of the demanded type. If this is not the case, an exception will be thrown. For instance, the function hire()
expects an argument of type Player
.
public function hire(Player $player)
{
$this->team[] = $player;
}
Dependencies
In general, we talk about dependencies when the instantiation of an object (or usage of a method) depends on other object instances.
class Flower
{
public function __constructor(Water $water, Sun $sun)
}
Managing dependencies, is a major topic in the design of your web application. In general, the fewer dependencies a class has, the better will be its handling, refactoring and testing. Concepts in this field are tight- and loose coupling. However, there explanation is beyond this rather basic introduction to OOP.
Statics and Constants
Static methods and properties are not based upon an instance of an object, instead they are globally accessible and thus can not be changed on an instance basis. In other words, a static method or property of an object will share throughout all instances the same value or behavior.
NOTE: Static methods and properties should be applied with caution, as they can easily brake your application. Only apply it, if you are certain about a proper use case.
Static method
Example of static methods are Laravel's helper functions.
public static function contains($haystack, $needles)
{
foreach ((array) $needles as $needle) {
if ($needle !== '' && mb_strpos($haystack, $needle) !== false) {
return true;
}
}
return false;
}
Static Property
This example stresses the fact that static variables can not be changed on a instance basis but only globally.
class Chair
{
static $size = 'medium';
}
$mychair = new Chair();
$yourchair = new Chair();
var_dump(Chair::$size); // medium
$yourchair::$size = 'small';
var_dump($yourchair::$size); // small
var_dump($mychair::$size); // small
Constant Property
A constant property can not be changed.
const TAX = 0.19;
var_dump(TAX); // 0.19
const TAX = 0.10; // PHP notice const TAX already defined
var_dump(TAX); // 0.19
Interfaces
What are interfaces? A list of public methods that must be defined by all objects that implement the interface. Consider the following example of a mailer interface
. Each function that implements this interface need to provide a send()
method with the arguments $from
, $to
, and $message
.
interface Mailer
{
public function send($from, $to, $message);
}
class WelcomeMailer implements Mailer
{
public function send ()
{
//
}
}
class ForgotPasswortMailer implements Mailer
{
public function send ()
{
//
}
}
class SuggestedContentMailer implements Mailer
{
public function send ()
{
//
}
}
Contract for implementations
Think of an interface as the contract for your implementations. It is the place were you define the public interface (= no private and protected methods) that you are going to use in your implementations. You do not define any logic in interfaces. A class can implement multiple interfaces.
class Example implements InterfaceA, InterfaceB
{
// methods
}
Why are interfaces relevant? They offer the following advantages:
- Flexible: Your methods become interchangeable because they are developed upon the same interface
- Maintainable: If a new feature is requested, a new implementation can be easily developed and integrated within the existing interface
Interface vs abstract class
We should look at it from two perspectives - methods and variables.
Methods:
- Interfaces: Methods are defined without a body, and therewith without any logic. Classes that implement this interface, must have a method with this name, despite of the implemented logic.
- Abstract classes: A method can be defined with a body. If the body wont be overwritten by the respective sub class, it is going to implement the same logic.
Variables:
- Interfaces: You can not define any variables within interfaces
- Abstract classes: You can define private, public, and protected variables.
Further resources
- OOP bootcamp by Jeffrey Way on Laracast.com
- OOP Guide on php-einfach.de [German]