My understanding is that a facade is used as an alternative to dependency injection. Please correct if I'm mistaken. What is not clear is when one should use one or the other.
What are the advantages/disadvantages of each approach? How should I determine when to use one or the other?
Lastly, why not use both? I can create a facade that references an interface. It seems Sentry 2 is written this way. Is there a best practice?
Facades, as noted, are intended to simplify a potentially complicated interface.
Facades are still testable
Laravel's implementation goes a step further and allows you to define the base-class that the Facade "points" to.
This gives a developer the ability to "mock" a Facade - by switching the base-class out with a mock object.
In that sense, you can use them and still have testable code. This is where some confusion lies within the PHP community.
DI is often cited as making your code testable - they make mocking class dependencies easy. (Sidenote: Interfaces and DI have other important reasons for existing!)
Facades, on the other hand, are often cited as making testing harder because you can't "simply inject a mock object" into whatever code you're testing. However, as noted, you can in fact "mock" them.
Facade vs DI
This is where people get confused regarding whether Facades are an alternative to DI or not.
In a sense, they both add a dependency to your class - You can either use DI to add a dependency or you can use a Facade directly -
FacadeName::method($param);
. (Hopefully you are not instantiating any class directly within another :D ).This does not make Facades an alternative to DI, but instead, within Laravel, does create a situation where you may decide to add class dependencies one of 2 ways - either using DI or by using a Facade. (You can, of course, use other ways. These "2 ways" are just the most-often used "testable way").
FACADES
Facades are not an alternative to dependency injection.
Laravel Facade is an implementation of the Service Locator Pattern, creating a clean and beautiful way of accessing objects:
This is the PHP syntax for a static methods, but Laravel changes the game and make them non-static behind the scenes, giving you a beautiful, enjoyable and testable way of writing your applications.
DEPENDENCY INJECTION
Dependency Injection is, basically, a way of passing parameters to your constructors and methods while automatically instatiating them.
A better construction of it would be using Interfaces on your Dependency Injected constructors:
But note that in Laravel you can inject classes and interfaces the same way. To inject interfaces you just have to tell it wich one will be this way:
This will tell Laravel that every time one of your methods needs an instance of MyInterface it should give it one of MyOtherClass.
What happens here is that this constuctor has a "dependency":
MyOtherClass
, which will be automatically injected by Laravel using the IoC container. So, when you create an instance ofMyClass
, Laravel automatically will create an instance ofMyOtherClass
and put it in the variable$class
.Dependency Injection is just an odd jargon developers created to do something as simple as "automatic generation of parameters".
WHEN TO USE ONE OR THE OTHER?
As you can see, they are completely different things, so you won't ever need to decide between them, but you will have to decide where go to with one or the other in different parts of your application.
Use Facades to ease the way you write your code. For example: it's a good practice to create packages for your application modules, so, to create Facades for those packages is also a way to make them seem like a Laravel public class and accessing them using the static syntax.
Use Dependency Injection every time your class needs to use data or processing from another class. It will make your code testable, because you will be able to "inject" a mock of those dependencies into your class and you will be also exercising the single responsibility principle (take a look at the SOLID principles).
Laravel's Facades are an implementation of the Service Locator pattern, not the Facade pattern.
In my opinion you should avoid service locator within your domain, opting to only use it in your service and web transport layers.
http://martinfowler.com/articles/injection.html#UsingAServiceLocator
I think that in terms of laravel Facades help you keep you code simple and still testable since you can mock facades however might be a bit harder to tell a controllers dependencies if you use facades since they are probably all over the place in your code.
With dependency injection you need to write a bit more code since you need to deal with creating interfaces and services to handle the depenancies however Its a lot more clear later on what a controller depends on since these are clearly mentioned in the controller constructor.
I guess it's a matter of deciding which method you prefer using