### **Taking It Further** ###
Let's consider another example to solidify our understanding. Perhaps we want to notify customers of charges to their account. We'll define two interfaces, or contracts. These contracts will gie us the flexibility to change out their implementations later.
~~~
<!-- lang: php -->
interface BillerInterface {
public function bill(array $user, $amount);
}
interface BillingNotifierInterface {
public function notify(array $user, $amount);
}
~~~
Next we'll build an implementation of our ``BillerInterface`` contract:
~~~
<!-- lang:php -->
class StripeBiller implements BillerInterface{
public function __construct(BillingNotifierInterface $notifier)
{
$this->notifier = $notifier;
}
public function bill(array $user, $amount)
{
// Bill the user via Stripe...
$this->notifier->notify($user, $amount);
}
~~~
By separating the responsibilities of each class, we're now able to easily inject various notifier implementations into our billing class. For example, we could inject a ``SmsNotifier`` or an ``EmailNotifier``. Our biller is no longer concerned with the implementation of notifyingg, but only the contract. As long as a class abides by its contract (interface), the biller will gladly accept it. Furthermore, not only do we get added flexibility, we can now test our biller in isolation from our notifiers by injecting a mock ``BillingNotifierInterface``.
> **Be The Interface**
>
> While writing interfaces might seem to a lot of extra work, they can actually make your development more rapid. Use interfaces to mock and test the entire back-end of your application before writing a single line of implementation!
>
So, how do we do dependency injection? It's simple:
~~~
<!-- lang:php -->
$biller = new StripeBiller(new SmsNotifier);
~~~
That's dependency injection. Instead of the biller being concerned with notifying users, we simply pass it a notifier. A change this simple can do amazing things for your applications. Your code immediately becomes more maintainable since class responsibilities are clearly delineated. Also, testability will skyrocket as you can easily inject mock dependencies to isolate the code under test.
But what about IoC containers? Aren't they necessary to do dependency injection? Absolutely not! As we'll see in the following chapters, containers make dependency injection easier to manage, but they are not a requirement. By following the principles in this chapter, you can practice dependency injection in any of your projects, regardless of whether a container is avaliable to you.
- Dependency Injection
- The Problem
- Build A Contract
- Take It further
- Too Much Java?
- The IoC Container
- Basic Binding
- Reflective Resolution
- Interface As Contract
- Strong Typing & Water Fowl
- A Contract Example
- Interface & Team Development
- Service Provider
- As Bootstrapper
- As Organizer
- Booting Providers
- Providing The Core
- Application Structure
- MVC Is Killing You
- Bye, Bye Models
- It's All About The Layers
- Where To Put "Stuff"
- Applied Architecture: Decoupling Handles
- Decoupling Handlers
- Other Handlers
- Extending The Framework
- Manager & Factories
- Cache
- Session
- Authentication
- IoC Based Extension
- Request Extension
- Single Responsibility Principle
- Open Closed Principle