Backend

# Backend

This section wil give some back-end guidelines and rules to write better code.

# PSR-1 & PSR-2

Laravel and craft using these psr-1 and 2 coding standards.

# PSR-1

  • Files MUST use only <?php tags.
  • Files MUST NOT use <?= tags.
  • Files MUST use only UTF-8 without BOM for PHP code.
  • Files SHOULD either declare symbols (classes, functions, constants, etc.) or cause side-effects (e.g. generate output, change .ini settings, etc.) but SHOULD NOT do both.
  • Namespaces and classes MUST follow an "autoloading" PSR: [PSR-0, PSR-4].
  • Class names MUST be declared in StudlyCaps.
  • Class constants MUST be declared in all upper case with underscore separators.
  • Method names MUST be declared in camelCase.

# Files

# PHP Tags

PHP code MUST only use the long <?php ?> tags; According to PSR-1 you can use short tags, but at Beeldr we don't.

# Character Encoding

PHP code MUST use only UTF-8 without BOM.

# Side Effects

A file SHOULD declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it SHOULD execute logic with side effects, but SHOULD NOT do both. The phrase "side effects" means execution of logic not directly related to declaring classes, functions, constants, etc., merely from including the file. "Side effects" include but are not limited to: generating output, explicit use of require or include, connecting to external services, modifying ini settings, emitting errors or exceptions, modifying global or static variables, reading from or writing to a file, and so on. The following is an example of a file with both declarations and side effects; i.e, an example of what to avoid:

<?php
// side effect: change ini settings
ini_set('error_reporting', E_ALL);

// side effect: loads a file
include "file.php";

// side effect: generates output
echo "<html>\n";

// declaration
function foo()
{
    // function body
}

The following example is of a file that contains declarations without side effects; i.e., an example of what to emulate:

<?php
// declaration
function foo()
{
    // function body
}

// conditional declaration is *not* a side effect
if (! function_exists('bar')) {
    function bar()
    {
        // function body
    }
}

# Namespace and Class Names

  • Namespaces and classes MUST follow an "autoloading" PSR: [PSR-0, PSR-4].
  • This means each class is in a file by itself, and is in a namespace of at least one level: a top-level vendor name.
  • Class names MUST be declared in StudlyCaps.
  • Code written for PHP 5.3 and after MUST use formal namespaces.

For example:

<?php
// PHP 5.3 and later:
namespace Vendor\Model;

class Foo
{
}

Code written for 5.2.x and before SHOULD use the pseudo-namespacing convention of Vendor_ prefixes on class names.

<?php
// PHP 5.2.x and earlier:
class Vendor_Model_Foo
{
}

# Class Constants, Properties, and Methods

The term "class" refers to all classes, interfaces, and traits.

# Constants

Class constants MUST be declared in all upper case with underscore separators. For example:

<?php
namespace Vendor\Model;

class Foo
{
    const VERSION = '1.0';
    const DATE_APPROVED = '2012-06-01';
}
# Properties

This guide intentionally avoids any recommendation regarding the use of $StudlyCaps, $camelCase, or $under_score property names.

Whatever naming convention is used SHOULD be applied consistently within a reasonable scope. That scope may be vendor-level, package-level, class-level, or method-level.

# Methods

Method names MUST be declared in camelCase().

# PSR-2

  • Code MUST follow a "coding style guide" PSR [PSR-1].
  • Code MUST use 4 spaces for indenting, not tabs.
  • There MUST NOT be a hard limit on line length; the soft limit MUST be 120 characters; lines SHOULD be 80 characters or less.
  • There MUST be one blank line after the namespace declaration, and there MUST be one blank line after the block of use declarations.
  • Opening braces for classes MUST go on the next line, and closing braces MUST go on the next line after the body.
  • Opening braces for methods MUST go on the next line, and closing braces MUST go on the next line after the body.
  • Visibility MUST be declared on all properties and methods; abstract and final MUST be declared before the visibility; static MUST be declared after the visibility.
  • Control structure keywords MUST have one space after them; method and function calls MUST NOT.
  • Opening braces for control structures MUST go on the same line, and closing braces MUST go on the next line after the body.
  • Opening parentheses for control structures MUST NOT have a space after them, and closing parentheses for control structures MUST NOT have a space before.
# Example

This example encompasses some of the rules below as a quick overview:

<?php
namespace Vendor\Package;

use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class Foo extends Bar implements FooInterface
{
    public function sampleMethod($a, $b = null)
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }

    final public static function bar()
    {
        // method body
    }
}

# General

# Basic Coding Standard

Code MUST follow all rules outlined in PSR-1.

#####. Files

  • All PHP files MUST use the Unix LF (linefeed) line ending.
  • All PHP files MUST end with a single blank line.
  • The closing ?> tag MUST be omitted from files containing only PHP.
# Lines
  • There MUST NOT be a hard limit on line length.
  • The soft limit on line length MUST be 120 characters; automated style checkers MUST warn but MUST NOT error at the soft limit.
  • Lines SHOULD NOT be longer than 80 characters; lines longer than that SHOULD be split into multiple subsequent lines of no more than 80 characters each.
  • There MUST NOT be trailing whitespace at the end of non-blank lines.
  • Blank lines MAY be added to improve readability and to indicate related blocks of code.
  • There MUST NOT be more than one statement per line.
# Indenting
  • Code MUST use an indent of 4 spaces, and MUST NOT use tabs for indenting. N.b.: Using only spaces, and not mixing spaces with tabs, helps to avoid problems with diffs, patches, history, and annotations. The use of spaces also makes it easy to insert fine-grained sub-indentation for inter-line alignment.
# Keywords and True/False/Null
  • PHP keywords MUST be in lower case.
  • The PHP constants true, false, and null MUST be in lower case.

# Namespace and Use Declarations

  • When present, there MUST be one blank line after the namespace declaration.
  • When present, all use declarations MUST go after the namespace declaration.
  • There MUST be one use keyword per declaration.
  • There MUST be one blank line after the use block.

For example:

<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

// ... additional PHP code ...

# Classes, Properties, and Methods

The term "class" refers to all classes, interfaces, and traits.

# Extends and Implements
  • The extends and implements keywords MUST be declared on the same line as the class name.
  • The opening brace for the class MUST go on its own line; the closing brace for the class MUST go on the next line after the body.
<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
    // constants, properties, methods

Lists of implements MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line.

<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // constants, properties, methods
}
# Properties
  • Visibility MUST be declared on all properties.
  • The var keyword MUST NOT be used to declare a property.
  • There MUST NOT be more than one property declared per statement.
  • Property names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility.
  • A property declaration looks like the following.
<?php
namespace Vendor\Package;

class ClassName
{
    public $foo = null;
}
# Methods
  • Visibility MUST be declared on all methods.
  • Method names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility.
  • Method names MUST NOT be declared with a space after the method name. The opening brace MUST go on its own line, and the closing brace MUST go on the next line following the body. There MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis.
  • A method declaration looks like the following. Note the placement of parentheses, commas, spaces, and braces:
<?php
namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}
# Method Arguments
  • In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.
  • Method arguments with default values MUST go at the end of the argument list.
<?php
namespace Vendor\Package;

class ClassName
{
    public function foo($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

` Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line. When the argument list is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them.

<?php
namespace Vendor\Package;

class ClassName
{
    public function aVeryLongMethodName(
        ClassTypeHint $arg1,
        &$arg2,
        array $arg3 = []
    ) {
        // method body
    }
}
# abstract, final, and static
  • When present, the abstract and final declarations MUST precede the visibility declaration.
  • When present, the static declaration MUST come after the visibility declaration.
<?php
namespace Vendor\Package;

abstract class ClassName
{
    protected static $foo;

    abstract protected function zim();

    final public static function bar()
    {
        // method body
    }
}
# Method and Function Calls

When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis, there MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.

<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);

Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line.

<?php
$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);

# Control Structures

The general style rules for control structures are as follows:

  • There MUST be one space after the control structure keyword
  • There MUST NOT be a space after the opening parenthesis
  • There MUST NOT be a space before the closing parenthesis
  • There MUST be one space between the closing parenthesis and the opening brace
  • The structure body MUST be indented once
  • The closing brace MUST be on the next line after the body
  • The body of each structure MUST be enclosed by braces. This standardizes how the structures look, and reduces the likelihood of introducing errors as new lines get added to the body.
# if, elseif, else

An if structure looks like the following. Note the placement of parentheses, spaces, and braces; and that else and elseif are on the same line as the closing brace from the earlier body.

<?php
if ($expr1) {
    // if body
} elseif ($expr2) {
    // elseif body
} else {
    // else body;
}

The keyword elseif SHOULD be used instead of else if so that all control keywords look like single words.

# switch, case

A switch structure looks like the following. Note the placement of parentheses, spaces, and braces. The case statement MUST be indented once from switch, and the break keyword (or other terminating keyword) MUST be indented at the same level as the case body. There MUST be a comment such as // no break when fall-through is intentional in a non-empty case body.

<?php
switch ($expr) {
    case 0:
        echo 'First case, with a break';
        break;
    case 1:
        echo 'Second case, which falls through';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Third case, return instead of break';
        return;
    default:
        echo 'Default case';
        break;
}
# while, do while

A while statement looks like the following. Note the placement of parentheses, spaces, and braces.

<?php
while ($expr) {
    // structure body
}
Similarly, a do while statement looks like the following. Note the placement of parentheses, spaces, and braces.
```php
<?php
do {
    // structure body;
} while ($expr);
# for

A for statement looks like the following. Note the placement of parentheses, spaces, and braces.

<?php
for ($i = 0; $i < 10; $i++) {
    // for body
}
# foreach

A foreach statement looks like the following. Note the placement of parentheses, spaces, and braces.

<?php
foreach ($iterable as $key => $value) {
    // foreach body
}
# try, catch

A try catch block looks like the following. Note the placement of parentheses, spaces, and braces.

<?php
try {
    // try body
} catch (FirstExceptionType $e) {
    // catch body
} catch (OtherExceptionType $e) {
    // catch body
}

# Closures

Closures MUST be declared with a space after the function keyword, and a space before and after the use keyword.

The opening brace MUST go on the same line, and the closing brace MUST go on the next line following the body.

There MUST NOT be a space after the opening parenthesis of the argument list or variable list, and there MUST NOT be a space before the closing parenthesis of the argument list or variable list.

In the argument list and variable list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.

Closure arguments with default values MUST go at the end of the argument list.

A closure declaration looks like the following. Note the placement of parentheses, commas, spaces, and braces:

<?php
$closureWithArgs = function ($arg1, $arg2) {
    // body
};

$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
    // body
};

Argument lists and variable lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument or variable per line.

When the ending list (whether of arguments or variables) is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them.

The following are examples of closures with and without argument lists and variable lists split across multiple lines.

<?php
$longArgs_noVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) {
    // body
};

$noArgs_longVars = function () use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
    // body
};

$longArgs_longVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
    // body
};

$longArgs_shortVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use ($var1) {
    // body
};

$shortArgs_longVars = function ($arg) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
    // body
};

Note that the formatting rules also apply when the closure is used directly in a function or method call as an argument.

<?php
$foo->bar(
    $arg1,
    function ($arg2) use ($var1) {
        // body
    },
    $arg3
);

# PHP Linter

To help implementing the above standaards you can add : PHP Coding Standards Fixer (opens new window)

Also integratable in php storm PHPSTORM & PHP CS Fixer (opens new window)

If you want phpfixer to fix you're code when trying to commit. You can add a pre-commit hook.

 touch .git/hook/pre-commit && chmod +x .git/hook/pre-commit
 nano .git/hook/pre-commit

add below code to the pre-commit file and adjust the regex for your project

#!/usr/bin/env bash

echo "php-cs-fixer pre commit hook start"

PHP_CS_FIXER="vendor/bin/php-cs-fixer"
HAS_PHP_CS_FIXER=false

if [ -x $PHP_CS_FIXER ]; then
    HAS_PHP_CS_FIXER=true
fi

if $HAS_PHP_CS_FIXER; then
    FILES=`git status --porcelain | grep -E '^[AM] +(app|public|packages|tests|views).*\.php$' | cut -c 4- | tr '\n' ' '`
    if [ -z "$FILES" ]
	then
		  echo "No php files found in commit."
	else
		  echo ${FILES}
		  $PHP_CS_FIXER fix --rules=@PSR12 --verbose ${FILES}
		  git add ${FILES}
	fi
else
    echo ""
    echo "Please install php-cs-fixer, e.g.:"
    echo ""
    echo "  composer require --dev fabpot/php-cs-fixer:dev-master"
    echo ""
    exit 1
fi

echo "php-cs-fixer pre commit hook finish"

If you commit file not matching psr-12 then the fill will be fixt by CS Fixer.

# SOLID programming

Use the principles of SOLID programming when you can !

SOLID is an acronym for the first five object-oriented design (OOD) principles by Robert C. Martin

These principles establish practices that lend to developing software with considerations for maintaining and extending as the project grows. Adopting these practices can also contribute to avoiding code smells, refactoring code, and Agile or Adaptive software development.

SOLID stands for:

  • S - Single-responsiblity Principle
  • O - Open-closed Principle
  • L - Liskov Substitution Principle
  • I - Interface Segregation Principle
  • D - Dependency Inversion Principle

# Single-Responsibility Principle

Single-responsibility Principle (SRP) states:

A class should have one and only one reason to change, meaning that a class should have only one job.

For example, consider an application that takes a collection of shapes—circles, and squares—and calculates the sum of the area of all the shapes in the collection.

First, create the shape classes and have the constructors set up the required parameters.

For squares, you will need to know the length of a side:

class Square
{
public $length;

    public function construct($length)
    {
        $this->length = $length;
    }
}

For circles, you will need to know the radius:

class Circle
{
public $radius;

    public function construct($radius)
    {
        $this->radius = $radius;
    }
}

Next, create the AreaCalculator class and then write up the logic to sum up the areas of all provided shapes. The area of a square is calculated by length squared. The area of a circle is calculated by pi times radius squared.

class AreaCalculator
{
protected $shapes;

    public function __construct($shapes = [])
    {
        $this->shapes = $shapes;
    }

    public function sum()
    {
        foreach ($this->shapes as $shape) {
            if (is_a($shape, 'Square')) {
                $area[] = pow($shape->length, 2);
            } elseif (is_a($shape, 'Circle')) {
                $area[] = pi() * pow($shape->radius, 2);
            }
        }

        return array_sum($area);
    }

    public function output()
    {
        return implode('', [
          '',
              'Sum of the areas of provided shapes: ',
              $this->sum(),
          '',
      ]);
    }
}

To use the AreaCalculator class, you will need to instantiate the class and pass in an array of shapes and display the output at the bottom of the page.

Here is an example with a collection of three shapes:

  • a circle with a radius of 2
  • a square with a length of 5
  • a second square with a length of 6
$shapes = [
new Circle(2),
new Square(5),
new Square(6),
];

$areas = new AreaCalculator($shapes);

echo $areas->output(); The problem with the output method is that the AreaCalculator handles the logic to output the data.

Consider a scenario where the output should be converted to another format like JSON.

All of the logic would be handled by the AreaCalculator class. This would violate the single-responsibility principle. The AreaCalculator class should only be concerned with the sum of the areas of provided shapes. It should not care whether the user wants JSON or HTML.

To address this, you can create a separate SumCalculatorOutputter class and use that new class to handle the logic you need to output the data to the user:

class SumCalculatorOutputter
{
protected $calculator;

    public function __constructor(AreaCalculator $calculator)
    {
        $this->calculator = $calculator;
    }

    public function JSON()
    {
        $data = [
          'sum' => $this->calculator->sum(),
      ];

        return json_encode($data);
    }

    public function HTML()
    {
        return implode('', [
          '',
              'Sum of the areas of provided shapes: ',
              $this->calculator->sum(),
          '',
      ]);
    }
}

The SumCalculatorOutputter class would work like this:

$shapes = [
new Circle(2),
new Square(5),
new Square(6),
];

$areas = new AreaCalculator($shapes);
$output = new SumCalculatorOutputter($areas);

echo $output->JSON();
echo $output->HTML();

Now, the logic you need to output the data to the user is handled by the SumCalculatorOutputter class.

That satisfies the single-responsibility principle.

# Open-Closed Principle

Open-closed Principle (OCP) states:

Objects or entities should be open for extension but closed for modification.

This means that a class should be extendable without modifying the class itself.

Let’s revisit the AreaCalculator class and focus on the sum method:

class AreaCalculator
{
protected $shapes;

    public function __construct($shapes = [])
    {
        $this->shapes = $shapes;
    }

    public function sum()
    {
        foreach ($this->shapes as $shape) {
            if (is_a($shape, 'Square')) {
                $area[] = pow($shape->length, 2);
            } elseif (is_a($shape, 'Circle')) {
                $area[] = pi() * pow($shape->radius, 2);
            }
        }

        return array_sum($area);
    }
}

Consider a scenario where the user would like the sum of additional shapes like triangles, pentagons, hexagons, etc. You would have to constantly edit this file and add more if/else blocks. That would violate the open-closed principle.

A way you can make this sum method better is to remove the logic to calculate the area of each shape out of the AreaCalculator class method and attach it to each shape’s class.

Here is the area method defined in Square:

class Square
{
public $length;

    public function __construct($length)
    {
        $this->length = $length;
    }

    public function area()
    {
        return pow($this->length, 2);
    }
}

And here is the area method defined in Circle:

class Circle
{
public $radius;

    public function construct($radius)
    {
        $this->radius = $radius;
    }

    public function area()
    {
        return pi() * pow($shape->radius, 2);
    }
}

The sum method for AreaCalculator can then be rewritten as:

class AreaCalculator
{
// ...

    public function sum()
    {
        foreach ($this->shapes as $shape) {
            $area[] = $shape->area();
        }

        return array_sum($area);
    }
}

Now, you can create another shape class and pass it in when calculating the sum without breaking the code.

However, another problem arises. How do you know that the object passed into the AreaCalculator is actually a shape or if the shape has a method named area?

Coding to an interface is an integral part of SOLID.

Create a ShapeInterface that supports area:

interface ShapeInterface
{
public function area();
}

Modify your shape classes to implement the ShapeInterface.

Here is the update to Square:

class Square implements ShapeInterface
{
// ...
}

And here is the update to Circle:

class Circle implements ShapeInterface
{
// ...
}

In the sum method for AreaCalculator, you can check if the shapes provided are actually instances of the ShapeInterface; otherwise, throw an exception:

class AreaCalculator
{
// ...

    public function sum()
    {
        foreach ($this->shapes as $shape) {
            if (is_a($shape, 'ShapeInterface')) {
                $area[] = $shape->area();
                continue;
            }

            throw new AreaCalculatorInvalidShapeException();
        }

        return array_sum($area);
    }
}

That satisfies the open-closed principle.

# Liskov Substitution Principle

Liskov Substitution Principle states:

Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.

This means that every subclass or derived class should be substitutable for their base or parent class.

Building off the example AreaCalculator class, consider a new VolumeCalculator class that extends the AreaCalculator class:

class VolumeCalculator extends AreaCalculator
{
public function construct($shapes = [])
{
parent::construct($shapes);
}

    public function sum()
    {
        // logic to calculate the volumes and then return an array of output
        return [$summedData];
    }
}

Recall that the SumCalculatorOutputter class resembles this:

class SumCalculatorOutputter {
protected $calculator;

    public function __constructor(AreaCalculator $calculator) {
        $this->calculator = $calculator;
    }

    public function JSON() {
        $data = array(
            'sum' => $this->calculator->sum();
        );

        return json_encode($data);
    }

    public function HTML() {
        return implode('', array(
            '',
                'Sum of the areas of provided shapes: ',
                $this->calculator->sum(),
            ''
        ));
    }
}

If you tried to run an example like this:

$areas = new AreaCalculator($shapes); $volumes = new VolumeCalculator($solidShapes);

$output = new SumCalculatorOutputter($areas); $output2 = new SumCalculatorOutputter($volumes); When you call the HTML method on the $output2 object, you will get an E_NOTICE error informing you of an array to string conversion.

To fix this, instead of returning an array from the VolumeCalculator class sum method, return $summedData:

class VolumeCalculator extends AreaCalculator
{
public function construct($shapes = [])
{
parent::construct($shapes);
}

    public function sum()
    {
        // logic to calculate the volumes and then return a value of output
        return $summedData;
    }
}

The $summedData can be a float, double or integer.

That satisfies the Liskov substitution principle.

# Interface Segregation Principle

Interface segregation principle states:

A client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use.

Still building from the previous ShapeInterface example, you will need to support the new three-dimensional shapes of Cuboid and Spheroid, and these shapes will need to also calculate volume.

Let’s consider what would happen if you were to modify the ShapeInterface to add another contract:

interface ShapeInterface
{
public function area();

    public function volume();
}

Now, any shape you create must implement the volume method, but you know that squares are flat shapes and that they do not have volumes, so this interface would force the Square class to implement a method that it has no use of.

This would violate the interface segregation principle. Instead, you could create another interface called ThreeDimensionalShapeInterface that has the volume contract and three-dimensional shapes can implement this interface:

interface ShapeInterface
{
public function area();
}
interface ThreeDimensionalShapeInterface
{
public function volume();
}

class Cuboid implements ShapeInterface, ThreeDimensionalShapeInterface
{
public function area()
{
// calculate the surface area of the cuboid
}

    public function volume()
    {
        // calculate the volume of the cuboid
    }
}

This is a much better approach, but a pitfall to watch out for is when type-hinting these interfaces. Instead of using a ShapeInterface or a ThreeDimensionalShapeInterface, you can create another interface, maybe ManageShapeInterface, and implement it on both the flat and three-dimensional shapes.

This way, you can have a single API for managing the shapes:

interface ManageShapeInterface
{
public function calculate();
}

class Square implements ShapeInterface, ManageShapeInterface
{
public function area()
{
// calculate the area of the square
}

    public function calculate()
    {
        return $this->area();
    }
}

class Cuboid implements ShapeInterface, ThreeDimensionalShapeInterface, ManageShapeInterface
{
public function area()
{
// calculate the surface area of the cuboid
}

    public function volume()
    {
        // calculate the volume of the cuboid
    }

    public function calculate()
    {
        return $this->area();
    }
}

Now in AreaCalculator class, you can replace the call to the area method with calculate and also check if the object is an instance of the ManageShapeInterface and not the ShapeInterface.

That satisfies the interface segregation principle.

# Dependency Inversion Principle

Dependency inversion principle states:

Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module, but they should depend on abstractions.

This principle allows for decoupling.

Here is an example of a PasswordReminder that connects to a MySQL database:

class MySQLConnection
{
public function connect()
{
// handle the database connection
return 'Database connection';
}
}

class PasswordReminder
{
private $dbConnection;

    public function __construct(MySQLConnection $dbConnection)
    {
        $this->dbConnection = $dbConnection;
    }
}

First, the MySQLConnection is the low-level module while the PasswordReminder is high level, but according to the definition of D in SOLID, which states to Depend on abstraction, not on concretions. This snippet above violates this principle as the PasswordReminder class is being forced to depend on the MySQLConnection class.

Later, if you were to change the database engine, you would also have to edit the PasswordReminder class, and this would violate the open-close principle.

The PasswordReminder class should not care what database your application uses. To address these issues, you can code to an interface since high-level and low-level modules should depend on abstraction:

interface DBConnectionInterface
{
public function connect();
}
The interface has a connect method and the MySQLConnection class implements this interface. Also, instead of directly type-hinting MySQLConnection class in the constructor of the PasswordReminder, you instead type-hint the DBConnectionInterface and no matter the type of database your application uses, the PasswordReminder class can connect to the database without any problems and open-close principle is not violated.

class MySQLConnection implements DBConnectionInterface
{
public function connect()
{
// handle the database connection
return 'Database connection';
}
}

class PasswordReminder
{
private $dbConnection;

    public function __construct(DBConnectionInterface $dbConnection)
    {
        $this->dbConnection = $dbConnection;
    }
}

This code establishes that both the high-level and low-level modules depend on abstraction.