Is there any drawback with Laravel's use of fa

2020-07-29 02:23发布

问题:

There are some criticism [see below] to the Laravel's extensive use of facade, which seems is an anti-pattern, e.g.

Singleton "facades" only upside is that they are relatively "easy to use", but technical debt introduced from such shortcuts is hard to even estimate.

Sample code:

$value = Cache::get('key');

So, using the above example code, can anyone show me how this code can be better written in PHP, if we are not using facades?

回答1:

Disclaimer: I don't necessarily agree that facades are bad or an anti-pattern

A "better" way to do this would be using dependency injection. For example if this is your controller:

public function __construct(\Illuminate\Cache\Repository $cache){
    $this->cache = $cache;
}

public function doSomething(){
    $value = $this->cache->get('key');
}

Or you can do the same for just one method:

public function doSomething(\Illuminate\Cache\Repository $cache){
    $value = $cache->get('key');
}

Note that we're not type hinting the facade class here but the underlying framework class. You can find a list of these classes in the docs.



回答2:

$app['cache']->get('key');

Do you ever plan on moving your Laravel code-base outside of the Laravel Framework? If not, disregard these comments in my opinion, because that is the only noteworthy disadvantage of Facades.

But if you want to continue down that path, this article has an example that may help you. http://programmingarehard.com/2014/01/11/stop-using-facades.html



回答3:

I think Laravel does facades right in that they are really just aliases for classes which are actually proxies for resolving the underlying classes from the IoC container. This alleviates most of the problems when trying to test code which may use them. Resolving them from the IoC container yourself is really just doing what Laravel is already doing under the hood while in my opinion sacrificing readability of your code.

In the case of testing, the facades can easily be mocked with Cache::shouldReceive('someFunction')->...

From a design standpoint, you can swap implementations by modifying the service provider so that your implementation is chosen over the default one when resolving from the IoC container using the facade. That should give you the same advantages as dependency injection would give you while maintaining readability of your code.

I think the main issue here is that these aren't facades in their traditional sense and this causes a lot of confusion.



回答4:

Since you've tagged unit testing, you should keep in mind that static access facades like Laravel's ones make it very hard to accomplish the Isolation principle of unitary tests.

It is impossible (as far as I know) to stub or mock an static-accessed class or method, because you need to be nominative about it.

Another problem you might get is if you need to change the way your application does caching. While you are able to rely solely on Laravel, that's fine, but in the moment you need it to change, you will have to seek for all Cache::get('key') occurrences in order to refactor.

As @lukasgeiter pointed, a better approach would be to use Dependency Injection, through a Dependency Injection Container, such as Pimple.