Published Feb 20, 2019 / 7 min read

Diving into OOP

Introduction

This article is based upon an OOP bootcamp taught by Jeffrey Way on Laracast. It comprises my course notes along with personal code examples.

Let's dive into it and create a football player. In object oriented programming terms we use a different terminology: We create an oName spacing and auto loadingbjects of 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, 0

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. For a class perspective this may be attributes. Variables in PHP always start with the $ sign, are case sensitive and must either start with a letter (A-Z, a-z) or an _.

Methods

A method is a function within a class. It defines certain behavior of a class.

Scope

Scope refers to the visibility of variables and methods. We differentiate among three different types of visibility:

Protection and Security

The e-mail address of $user is only available if the profile is public. We realize 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());

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 Shape that defines that every sub-class gets a default color green if no other one will be 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 funtction getArea($base, $height)
    {
        return .5 $this->base * $this->height;
    }
}

Override attributes & behavior

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.

In the example above the following code would force an error.

$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 interface. In deed, 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 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 w ill 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 objects instances.

class Flower
{
   public function __constructor(Water $water, Sun $sun)
}

Managing dependencies, is a major topic in the design of your we 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 contants

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 interfaces 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
{
    //
}

Why are interfaces relevant? They offer the following advantages:

Interface vs abstract class

Methods

Variables

Further resources