This is one of those more advanced topics that took me a really long time, and lots of trial and error to figure out why and when I would use it. I’ll do my best to explain it the way that made me understand it.

Scenario: You have a custom e-commerce site that takes payments through Stripe. After a while you decide you want to change your payment processor to PayPal.

Before Pattern: You have to rewrite every part of the application that references Stripe.

After Pattern: You update one line in a service provider and you’re done.

So what do we have to do?

  1. Create the interface
  2. Create the implementation
  3. Bind them together

Create the interface

We are going to create a folder called Billing in our app/Services directory.

Inside that Billing folder in order to keep organized, we’re going to make a Contracts folder.

Note: We call them “Contracts” because it is going to serve as a set of “rules” that the implementations have to adhere to.

Create BillingContract.php inside the app/Services/Billing/Contracts folder:

We will add 1 method for demonstration purposes, but normally it would be full of methods that your implementations had to adhere to.

So this interface is saying that whatever class implements this contract, must have the method charge() publicly available.

Create the implementation

Next we have to create the class that will handle all of the work, in this example we are going to use Stripe as our payment processor.

So first we will create our StripeGateway.php class in app/Services/Billing:

As you can see we have created a class StripeGateway that implements our BillingContract. This tells the PHP interpreter that our StripeGateway class MUST have at least one method called charge().

If we removed the charge method form StripeGateway we would get an error stating that we must include all methods in the contract.

Now we have to tell Laravel that every time we instantiate our BillingContract, we want it to reference the StripeGateway class.

Bind the implementation to the contract

So we have all of the tools needed to bill the customer, but Laravel still does not know that the StripeGateway is friends with the BillingContract.

This is where a service provider comes in handy, it lets you tell the application as it’s booting that when I call BillingContract anywhere, I want you to use StripeGateway. (This may not make sense yet, but it will soon).

So lets create BillingServiceProvider.php in app/Providers:

The last thing we need to do is tell Laravel to load our new service provider, this is done in config/app.php file in the providers array:

Now, and only now, will Laravel know which implementation to use for our contract.

Seeing it in action

So now everything is all set up, you are ready to bill some customers. Here is a mock billing controller:

Ok so what is happening here?!

  1. The user hits the route to be billed
  2. As the BillingController is instantiated the constructor resolves the BillingContract class out of the Service Container, and Laravel now knows you want to bill via Stripe.
  3. The create method is hit, the charge method on the StripeGateway class processes the request.
  4. The user is redirected to a route with a success message.

So this is all fine and dandy, but what is the whole point?

So back to our scenario, we have Stripe, and now all of a sudden our boss wants us to use PayPal. What do we do?

  1. Create a new PayPalGateway class in app/Services/Billing
  2. Update the binding in BillingServiceProvider to call PayPalGateway instead of StripeGateway. Now everywhere you have instantiated BillingContract will use PayPalGateway.

Now it’s easy to swap out implementations of core functionality of your app without having to restructure all of your files! Hope this helps those of you who are having a hard time understanding this concept.