Tags

, , , ,

object oriented design patterns in php

object oriented design patterns in php


Object Oriented Design Patterns in PHP 7

Gang of Four!

How about starting this discussion by quoting from them?

Their famous book “Design Patterns, Elements of Reusable Object-Oriented Software”; and they are Erich Gamma, Richard Helm, Ralph Johnson and

John Vlissides.

The book starts with this meaningful statement— “Designing object-oriented software is hard, and designing reusable object-oriented software is even harder. You must find pertinent objects, factor them into classes at the right granularity, define class interfaces and inheritance hierarchies, and establish key relationships among them.

Your design should be specific to the problem at hand but also general enough to address future problems and requirements. You also want to avoid redesign, or at least minimize it. Experienced object-oriented designers will tell you that a reusable and flexible design is difficult if not impossible to get “right” the first time. Before a design is finished, they usually try to reuse it several times, modifying it each time.

Yet experienced object-oriented designers do make good designs. Meanwhile, new designers are overwhelmed by the options available and tend to fall back on non-object-oriented techniques they’ve used before. It takes a long time for novices to learn what good object-oriented design is all about. Experienced designers evidently know something inexperienced ones don’t. What is it?”

This introductory paragraph ends with a question mark.

I will always encourage you to read the book itself; a must read, however, at the same time I would like to start our discussion keeping this question mark in the background — “Experienced designers evidently know something inexperienced ones don’t. What is it?”

I have no doubt that “Single Responsibility Principle” or SRP is one of the most important concepts in object-oriented design, which experience designers know and follow from the beginning, and the inexperienced designers do not understand that core concept. And, it makes a real big difference.

Let us start with the core concept that sits right in the heart of SRP — classes should not do far too many things. Yes, a class can do many things for an object; but, you cannot abuse that power. It could cause unexpected harm to the organization of code in general. When a gentle tap with a hammer works fine, why strike the nail with a huge force? It may have a boomerang effect.
Thinking before and designing properly is entirely a different activity than getting the software to work. We always try to make our code work fast; keeping no rooms for organization and cleanliness.

It’s a wrong approach and it causes lots of harm to the effectiveness as a whole. When the program works, we are done; we forget that maintaining a separation of concerns is as important an activity in our programming design as it is in the running program. The real problem starts with the overstuffed classes that are burdened with too many tasks. They are not ‘decoupled units’ with single responsibility principles. Large numbers of small, single-purpose classes are like many caskets with well-defined-labels; this type of organization makes our tasks easier to find the appropriate things than dumping all staff in one single casket.

So we need many small classes, not a few large ones staffed with too many tasks. Each small class should have single responsibility encapsulated in a way so that they have a single reason to change. They will also communicate with a few other small classes to get the desired result. In the final chapter, we will build an MVC patterned framework keeping these single responsibility principles and separation of concerns intact.

Hopefully, you have started guessing how does Composer fit into this big picture. Actually, that is the reason why every good PHP framework such as Symfony or Laravel depends on this dependency management system. What is more, Composer has now become the standard of dependency management.

You can always use Composer project wise. Although, it is always good to install it in your system globally so that you can run it anywhere in your system. Let us install it globally. For any Debian based Linux distribution it is simple.
//code 1
ss@ss-Lenovo-3000-G530:/$ php -r “copy(‘https://getcomposer.org/installer', ‘composer-setup.php’);”
ss@ss-Lenovo-3000-G530:/$ php -r “if (hash_file(‘SHA384’, ‘composer-setup.php’) === ‘544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061’) { echo ‘Installer verified’; } else { echo ‘Installer corrupt’; unlink(‘composer-setup.php’); } echo PHP_EOL;”
Installer verified
ss@ss-Lenovo-3000-G530:/$ php composer-setup.php
All settings correct for using Composer
Downloading…
Composer (version 1.6.5) successfully installed to: //composer.phar
Use it: php composer.phar
ss@ss-Lenovo-3000-G530:/$ sudo php composer-setup.php — install-dir=/usr/local/bin — filename=composer
All settings correct for using Composer
Downloading…
Composer (version 1.6.5) successfully installed to: /usr/local/bin/composer
Use it: php /usr/local/bin/composer

In the first half, I have downloaded the Composer installer in my root directory and I have verified the product. After that, I have chosen the directory “usr/local/bin/composer” to set it up so that I can use it globally.
Next, I will check whether it works or not.
In “var/www/html” directory I have created a folder called “test-composer” and initialize the newly-installed composer into it.
//code 2
ss@ss-Lenovo-3000-G530:/var/www/html/test-composer$ composer init

Welcome to the Composer config generator
This command will guide you through creating your composer.json config.
Package name (/) [root/test-composer]: ss/mvc
Description []: mvc
Author [, n to skip]: n
Minimum Stability []: stable
Package Type (e.g. library, project, metapackage, composer-plugin) []: project
License []:
Define your dependencies.
Would you like to define your dependencies (require) interactively [yes]? y
Search for a package: cocur/slugify
Enter the version constraint to require (or leave blank to use the latest version):
Using version ^3.1 for cocur/slugify
Search for a package:
Would you like to define your dev dependencies (require-dev) interactively [yes]?
Search for a package:
{
“name”: “ss/mvc”,
“description”: “mvc”,
“type”: “project”,
“require”: {
“cocur/slugify”: “³.1”
},
“minimum-stability”: “stable”
}
Do you confirm generation [yes]? Y

Hitting the “enter” button, I have successfully created a “composer.json” file inside the test folder. Now, I can install Composer.
//code 3
ss@ss-Lenovo-3000-G530:/var/www/html/test-composer$ composer install
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
 — Installing cocur/slugify (v3.1): Downloading (100%)
Writing lock file
Generating autoload files
ss@ss-Lenovo-3000-G530:/var/www/html/test-composer$

Composer has been successfully installed. We can check the directory listing.
//code 4
ss@ss-Lenovo-3000-G530:/var/www/html/test-composer$ ls
composer.json composer.lock vendor

Now, you can use the “slugify” object to convert your any string into a slug. It can provide a good support to our MVC patterned framework. Not only that, we need to leverage the resources of other useful packages, available in “Packagist — The PHP Package Repository” (https://packagist.org/).
Solving every problem from first principles is not a good idea at all.

Effective patterns always reuse solutions that have worked for them in the past so that we can use it again and again. The combination of Composer and other PHP Packages solves a great problem that we have faced over the time.
There are recurring patterns of classes and communicating objects in many object-oriented systems, however, the availability of these patterns was extremely scarce in the past. We didn’t do enough job of recording experiences for others to do. If they did, there would not have been a good common resource to pull recurring patterns from it.

Using the combination of Composer and Packagist now we can not only find a package, we can also find all its dependencies and related library, meta package, and composer-plugin. Even PEAR packages are there to assist in your project’s decision-making process.

Composer and Separation of Concerns

One of the major design principles is “separation of concerns”.

Composer helps us to achieve that software design principle quite easily. This principle reminds us of two main factors — the first one is, every class should have a single responsibility. The second one is, the single responsibility of any class should be encapsulated by that class itself. Let us see how it works.
Before going to write the codes, let us design it properly. At the end of this book, we will build an MVC framework from the scratch. Keeping that in our mind, let me create a folder first in my “/var/www/html” directory. Let us name that folder “mymvc”.

Let us separate the output from our application logic. So we create two folders “src” and “public” in our “mymvc” application. In “public” folder, we have three folders — “css”, for keeping our CSS style files; “js” for JavaScript files; and “images” for keeping images. We also have an “index.php” file in our “public” folder as it will act as an entry point to our MVC web application.

Now, let us think about the “src” (it actually represents the word “source” or “resource”) folder. We must have “controllers”, “models”, and “views” folders for keeping our related classes. I have created another special folder called “kernel”, to keep special classes to maintain the separation of concerns. We will also have “init.php” file for initializing the application logic.
Let us see, how using Composer, we can maintain this separation of concerns.
The “composer.json” file looks like this:
//code 5
//composer.json
{
“autoload”: {

“psr-4”: {
“App\\”: “src/”,
“Controller\\”: “src/controllers”,
“Kernel\\”: “src/karnel”,
“Model\\”: “src/models”,
“View\\”: “src/views”

}

}
}

The file structure is quite simple to follow. Now, we can run the Composer and create the “../vendor/autoload.php” file.

The entry point of our application, that is, the “index.php” file must require this “init.php” file so that we can create an instance of our “App” there.
The code of “index.php” file looks like this:
//code 6
//public/index.php
<?php
require_once ‘../src/init.php’;
use Karnel\Apply as Apply;
$app = new Apply;

Here, “$app” represents our application instance. And the code of “init.php” file looks like this:
//code 7
<?php
require_once ‘../vendor/autoload.php’;
use Karnel\Error as Error;
$error = new Error;

We want to display errors on our every production page to follow the flow correctly. So, we keep a separate “Error” class for that in our “kernel” folder. In some cases, “display_errors” modules are commented out in “php.ini” file. This “$error” instance will also help us understand the separation of concerns principle.

The code of “Error.php” page is like this.
//code 3.8
//src/Karnel/Error.php
<?php namespace Karnel;
/*
* To display PHP errors on every page
*/
class Error
{
public function __construct() {

ini_set(‘display_errors’, 1);
ini_set(‘display_startup_errors’, 1);
error_reporting(E_ALL);

}
}

This “Error” class could be a perfect example of single responsibility if it had not violated the separation of concerns principle. But, it violates the separation of concerns principle.

Why? It is because with each initialization a part of our application logic directly hits the output. The same thing is true for our application instance. Let us see the “Apply” class code.
//code 3.9
//src/Karnel/Apply.php
parsingURL();

}

public function parsingURL() {

if (isset($_GET[‘url’])) {
$string = filter_var(rtrim($_GET[‘url’], ‘/’), FILTER_SANITIZE_URL);
$url = explode(‘/’, $string);
print_r($url);

}

}

}

Now, if we type in the browser like this:
http://localhost/mymvc/public/hello/world/from/sanjib
We get an output like this:
Array ( [0] => hello [1] => world [2] => from [3] => sanjib )

There are other mechanisms like using “.htaccess” file in our “public” folder. So that we can parse the URL in our “Apply” class. The code of “.htaccess” file is like this:
//code 10
//public/.htaccess
Options -MultiViews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?url=$1

I am not explaining the code here, because, I assume you have an initial PHP training to grasp the idea.

For this discussion, let us concentrate on the output I have got on my browser. It is an array where the $url[0] is “home”. The $url[1] is index and so on. Now, we can make one thing out of this output. We can make this “home” as our primary controller; it could be “home” controller and the “index” could be its method. What is more, we can pass other array values as the parameters of the “index” method.

I can build a “Home” controller class and through an “index” method I can pass the value to a “view” page. All I need to take care of one thing. The Controller class should not know “too much”. This will violate our “separation of concerns” principle, which is a key factor in effective patterns in PHP.

Here I want to emphasize one key aspect of Composer. It helps us by allowing us to use “namespace” and “file structure” to achieve the separation of concerns principle. While making the controller classes we should take care of one thing — the controller should not know where the data comes from and where it goes. It should not hit the database directly. It should not be tightly coupled.

In that way, we can successfully separate our business logic and output.

If you are interested, you can get the whole code sample in my GIT repository: https://github.com/sanjibsinha/mymvc