Hot File

Dependency Injection with Pimple in PHP

View: 354    Dowload: 0   Comment: 0   Post by: hanhga  
Author: none   Category: Forum PHPBB, VBB   Fields: Other

10 point/3 review File has been tested

In application development, we try to create independent modules so that we can reuse code in future projects. But, it’s difficult to create completely independent modules which provide useful functionality; their dependencies can cause maintenance nightmares unless they are managed properly.

Introduction

In application development, we try to create independent modules so that we can reuse code in future projects. But, it’s difficult to create completely independent modules which provide useful functionality; their dependencies can cause maintenance nightmares unless they are managed properly. This is where Dependency Injection comes in handy, as it gives us the ability to inject the dependencies our code needs to function properly without hard coding them into the modules.

Pimple is a simple dependency injection container which takes advantage PHP’s closures to define dependencies in manageable way. In this article we’ll look at the problems with hard-coding dependencies, how dependency injection solves them, and how to use Pimple to keep code that takes advantage of dependency injection more maintainable.

The Issues with Concrete Dependencies

We use a number of PHP classes when writing applications. One class may need to call methods of one or more other classes to provide the intended functionality, and so we say the first class depends on the other classes. For example:

<?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}

Class A depends on class B. If class B is not available then the above code will not work.

Moreover, every time we hard code the creation of an object inside a class, we are making a concrete dependency to that class. Concrete dependencies are a barrier to writing testable code. A better way is to provide an object of class B to class A. These objects can be provided through A’s constructor or a setter method.

Let’s take a look at a more realistic scenario before we go any further.

Sharing content on social networking websites is very common these days, and most sites display their social profile feeds right on their site itself. Suppose we have a class called SocialFeeds which generates feeds from social sites like Twitter, Facebook, Google+, etc. Separate classes are created to work with each of these services. Here we’ll look at the class that interfaces with Twitter,TwitterService.

The SocialFeeds class requests a Twitter feed using TwitterServiceTwitterService interacts with the database to retrieve the specific user token to access the API. The token is passed to the OAuthclass which retrieves the feeds using the provided token and returns it to the SocialFeeds class.

<?php
class SocialFeeds
{
    public function getSocialFeeds() {
        $twService = new TwitterService();
        echo $twService->getTweets();
    }
}
<?php
class TwitterService
{
    public function getTweets() {
        $db = new DB();
        $query = "Query to get user token from database";
        $token = $db->getQueryResults($query);

        $oauth = new OAuth();
        return $oauth->requestTwitterFeed($token);
    }
}
<?php
class OAuth
{
    public function requestTwitterFeed($token) {
        // Retrieve and return twitter feed using the token     
    }
}
<?php
class DB
{
    public function getQueryResults($query) {
        // Get results from database and return token
    }
}

It’s clear that SocialFeeds depends on TwitterService. But TwitterService depends on DB andOAuth, and so SocialFeeds depends on both DB and OAuth indirectly.

So what are the issues? SocialFeeds depends on concrete implementations of three classes, so it is impossible to test SocialFeeds as a separate unit without having real implementations of the other classes. Or, let’s say we want to use a different database or a different OAuth provider. In this case we would have to replace the existing classes with new class in each occurrence throughout our code.

Fixing Concrete Dependencies

The solution to these dependency issues is as simple as providing the objects dynamically when necessary without using concrete implementations. There are two types of techniques to inject dependencies: constructor-based dependency injection and setter-based injection.

Constructor-Based Injection

With constructor-based dependency injection, dependant objects are created externally and passed to the class’s constructor as parameters. We can assign these objects to class variables and use anywhere inside the class. Constructor-based injection for the SocialFeeds class looks like this:

<?php
class SocialFeeds
{
    public $twService;

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

    public function getSocialFeeds() {
        echo $this->twService->getTweets();
    }
}

An instance of TwitterService is passed as an object to the constructor. SocialFeeds still depends on TwitterService, but now we can have the freedom to provide different versions of the Twitter service provider or even a mock object for testing purposes. The DB and OAuth classes are defined similarly with regard to TwitterService.

<?php
$db = new DB();
$oauth = new OAuth();
$twService = new TwitterService($db, $oauth);
$socialFeeds = new SocialFeeds($twService);
$socialFeeds->getSocialFeeds();

Setter-Based Injection

With setter-based injection, objects are provided through setter methods instead of the constructor. Here’s a setter-based implementation of dependency injection for the SocialFeeds class:

<?php
class SocialFeeds
{
    public $twService;

    public function getSocialFeeds() {
        echo $this->twService->getTweets();
    }

    public function setTwitterService($twService) {
        $this->twService = $twService;
    }
}

The initialization code including DB and OAuth for now looks like this:

<?php
$db = new DB();
$oauth = new OAuth();
$twService = new TwitterService();
$twService->setDB($db);
$twService->setOAuth($oauth);

$socialFeeds = new SocialFeed();
$socialFeeds->setTwitterService($twService);
$socialFeeds->getSocialFeeds();

Constructor vs Setter Injection

It’s up to you to choose between constructor or setter-based injection. Constructor-based injections are suitable when all the dependencies are required in order to instantiate the class. Setter-based injections are suitable when dependencies are not required in each occasion.

Advantages

Constructor – all the dependencies of a class are identifiable simply by looking at the class’s constructor

Setter – adding a new dependency is as easy as adding a new setter method, which does not break existing code

Disadvantages

Constructor – adding a new dependency increases the constructor’s parameters; existing code needs to be updated throughout our application to provide the new dependency

Setter – we have to manually search for the necessary dependencies as they are not specified anywhere

With knowledge of dependency injection and various injection techniques, it’s time to look at Pimple and see how it fits in.

The Role of Pimple in DI

You might be wondering why Pimple is necessary when we can inject the dependencies already using the techniques previously mentioned. To answer this question, we need to look to the DRY principle.

Consider the constructor-based injection example. Each time we want an object of the SocialFeedclass, we have to repeat the whole setup process of instantiating and passing its dependencies. According to DRY, such code should be avoided to prevent maintenance headaches. Pimple acts as a container for defining such dependencies to avoid repetition.

Let’s look at a simple example to see how Pimple works.

<?php
$container = new Pimple();
$container['class_name'] = 'Test';
$container['object_name'] = function ($c) {
    return new $c['class_name']();
};

$testClass = $container['object_name'];

An instance of Pimple is created to act as the container for storing dependencies. It implements the SPLArrayAccess interface so working with it is very similar to working with an array. First we’ve defined a key which holds the name of some arbitrary class we want. Then we’ve defined a closure to return the instance of the specified class which acts as a service. Note that $c will be passed an instance of the container, so we can reference other defined keys as we please; each defined parameter or object is available in the closure through the $c variable. Now whenever we want an instance of the class, we can reference the key to retrieve the object.

Let’s convert the SocialFeeds example to Pimple. The examples on the official Pimple site show constructor-based injection, so here we’ll illustrate setter-based injection. Keep in mind that any of the setter methods or code we defined in earlier do not need to be modified for us to use Pimple – we simply encapsulate the logic.

<?php
$container = new Pimple();
$container['oauth'] = function($c) {
 return new OAuth();
};
$container['db'] = function($c) {
 return new DB();
};
$container['tweet_service'] = function($c) {
 $twService = new TwitterService();
 $twService->setDB($c['db']);
 $twService->setOauth($c['oauth']);
 return $twService;
};
$container['social_feeds'] = function($c) {
 $socialFeeds = new SocialFeeds();
 $socialFeeds->setTwitterService($c['tweet_service']);
 return $socialFeeds;
};

$socialFeeds = $container['social_feeds'];
$socialFeeds->getSocialFeeds();

Both DB and OAuth classes are independent modules, so we directly return a new instance of them inside closures. Then we add dependencies to the TwitterService class using setter-based injections. We added DB and OAuth classes into the container already, so we can directly access them inside the function using $c['db'] and $c['oauth'].

Now the dependencies are encapsulated inside the container as services. Whenever we want to use different DB class or different OAuth service, we can just replace the class inside the container statement and everything will work perfectly. With Pimple you need to add new dependencies in just one place.

Advanced Pimple Usage

In the above scenario, Pimple will return new instances of each class from the closure whenever one is requested. There are certain scenarios where we need to use the same object without initializing new instances each time, for example connecting to database is a perfect example.

Pimple provides the ability to return the same instance using sharing objects, doing so requires us to specify the closure through the share() method as shown below:

<?php
$container['db'] = $container->share(function ($c) {
    return new DB();
});

Also, so far we’ve defined all our dependencies in a single location inside the Pimple container. But think of a situation where we need the services with its dependencies but configured in a slightly different way than the original. For example, let’s say we need to access an ORM for certain functionality of theTwitterService class. We can’t change the existing closure since it will force all of the existing functionality to use the ORM.

Pimple provides the method extend() to modify the existing closure dynamically without affecting the original implementation. Consider the following code:

<?php
$container['tweet_service'] = $container->extend('tweet_service', function($twSservice, $c) {
 $twService->setDB(new ORM());
 return $twService;
});

Now we’re able to use different extended versions of tweet_service in special scenarios. The first parameter is the name of the service, the second is a function that gets access to the object instance and the container.

Indeed, extend() is a powerful way of adding dependencies dynamically to suit different situations, but make sure to limit the extended versions of services to a minimum as it increases the amount of duplicate code.

 

Dependency Injection with Pimple in PHP

Dependency Injection with Pimple in PHP Posted on 11-04-2016  In application development, we try to create independent modules so that we can reuse code in future projects. But, it’s difficult to create completely independent modules which provide useful functionality; their dependencies can cause maintenance nightmares unless they are managed properly. 3.3333333333333/10 354

Comment:

To comment you must be logged in members.

Files with category

  • Input Validation Using Filter Functions with php

    View: 437    Download: 0   Comment: 0   Author: none  

    Input Validation Using Filter Functions with php

    Category: Forum PHPBB, VBB
    Fields: Other

    2.25/2 review
    Filter functions in PHP might not be sexy, but they can improve the stability, security, and even maintainability of your code if you learn how to use them correctly.

  • The Open/Closed Principle in PHP

    View: 311    Download: 0   Comment: 0   Author: none  

    The Open/Closed Principle in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    0/2 review
    As usual, a good way to grasp what’s actually behind the curtain of the principle and how to take advantage of its benefits is by example. In this article I’ll be setting up a few approachable ones in an attempt to unveil the principle’s driving...

  • Dependency Injection with Pimple in PHP

    View: 354    Download: 0   Comment: 0   Author: none  

    Dependency Injection with Pimple in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    1.6666666666667/3 review
    In application development, we try to create independent modules so that we can reuse code in future projects. But, it’s difficult to create completely independent modules which provide useful functionality; their dependencies can cause maintenance...

  • Working with Directories in PHP

    View: 490    Download: 0   Comment: 0   Author: none  

    Working with Directories in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    2.25/2 review
    Let's start with simple listing the contents of a directory. We need three functions to perform this task: opendir(), readdir() and closedir(). The opendir() function takes one parameter, which is the directory we want to read, and returns a...

  • Guide to Email (Text / HTML / Attachments) in PHP

    View: 468    Download: 0   Comment: 0   Author: none  

    Guide to Email (Text / HTML / Attachments) in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    0/2 review
    At first let's consider how to send a simple text email messages. PHP includes the mail() function for sending email, which takes three basic and two optional parameters.

  • Dynamic Image Generation in PHP

    View: 392    Download: 0   Comment: 0   Author: none  

    Dynamic Image Generation in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    0/1 review
    At first, have a look at the following script that creates captcha image. Next, we will consider each step of image generation in details.

  • Form Processing with PHP

    View: 689    Download: 0   Comment: 0   Author: none  

    Form Processing with PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    2.6666666666667/3 review
    Before you can process the information, you need to create an HTML form that will send information to your PHP script. There are two methods for sending data: POST and GET. These two types of sending information are defined in your HTML form...

  • Function in PHP

    View: 577    Download: 0   Comment: 0   Author: none  

    Function in PHP

    Category: Forum PHPBB, VBB
    Fields: Other

    2.5/2 review
    A function is a block of code which can be called from any point in a script after it has been declared. It is basically a compartmentalized PHP script designed to accomplish a single task. Furthermore, code contained within functions is ignored...

 
Newsletter Email

File suggestion for you

File top downloads

logo codetitle
Codetitle.com - library source code to share, download the file to the community
Copyright © 2015. All rights reserved. codetitle.com Develope by Vinagon .Ltd