Façades


Quand utiliser les façades

Les façades présentent de nombreux avantages. Elles fournissent une syntaxe simple et facile à retenir qui élimine le besoin d'injecter ou de configurer manuellement des noms de classe longs. De plus, ils rendent les tests très faciles grâce à leurs appels uniques aux méthodes statiques PHP.

Cependant, certains endroits nécessitent une attention particulière lors de l’utilisation des façades. Le principal danger lors de l’utilisation de Facades est l’expansion de la portée des classes. Étant donné que les façades sont très simples à utiliser et ne nécessitent pas d'injection, nous pouvons par inadvertance utiliser plusieurs façades dans une seule classe, ce qui rend la classe de plus en plus grande. Cependant, lors de l'utilisation de l'injection de dépendances, plus on utilise de classes, plus le constructeur sera long. Visuellement, on remarquera que cette classe est un peu volumineuse. Par conséquent, lorsque vous utilisez Facades, portez une attention particulière au contrôle de la taille de la classe afin de conserver une portée courte.

{tip} Lors du développement de packages d'extension tiers qui interagissent avec Laravel, il est préférable d'injecter des contrats Laravel au lieu d'utiliser Facades. Étant donné que le package d'extension est construit en dehors de Laravel, vous ne pouvez pas utiliser Laravel Facades pour tester les fonctions d'assistance. cours injectés. Très utile lors des tests car vous pouvez injecter une simulation ou un stub et affirmer diverses méthodes sur le stub.

Habituellement, les méthodes véritablement statiques sont impossibles à simuler ou à écraser. Cependant, les façades utilisent des méthodes dynamiques pour proxy l'invocation des méthodes objet analysées dans le conteneur de services. Nous pouvons également tester les façades tout comme tester les instances de classe injectées. Par exemple, comme la route suivante :

use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {  
  return Cache::get('key');
 });
Nous pouvons écrire le code de test suivant avec les paramètres que nous attendons pour vérifier la méthode Cache::get :
use Illuminate\Support\Facades\Cache;
/**
 * 一个基础功能的测试。
 *
 * @return void
 */
 public function testBasicExample(){ 
    Cache::shouldReceive('get')   
          ->with('key')     
          ->andReturn('value');  
    $this->visit('/cache')   
        ->see('value');
    }

Façades Par rapport aux fonctions d'assistance

En plus des façades, Laravel contient également diverses "fonctions d'assistance" pour implémenter ces fonctions communes Par exemple, générer des vues, déclencher des événements, planifier des tâches ou envoyer des réponses HTTP. De nombreuses fonctions auxiliaires ont des façades correspondantes. Par exemple, les façades et fonctions d'assistance suivantes font la même chose :

return View::make('profile');return view('profile');

Il n'y a pas de réelle différence entre les façades et les fonctions d'assistance. Lorsque vous utilisez une fonction d'assistance, vous pouvez la tester tout comme la Façade correspondante. Par exemple, la route suivante :

Route::get('/cache', function () {    return cache('key');});
Cache::get 方法:

use Illuminate\Support\Facades\Cache;
/**
 * 一个基础功能的测试用例。
 *
 * @return void
 */
 public function testBasicExample(){ 
    Cache::shouldReceive('get')  
           ->with('key')    
           ->andReturn('value'); 
    $this->visit('/cache')  
        ->see('value');
     }

Facades 相较于辅助函数

除了 Facades,Laravel 还包含各种 『辅助函数』 来实现这些常用功能,比如生成视图、触发事件、任务调度或者发送 HTTP 响应。许多辅助函数都有与之对应的 Facades 。例如,下面这个 Facades 和辅助函数的作用是一样的:

<?php
   namespace App\Http\Controllers;
   use App\Http\Controllers\Controller;
   use Illuminate\Support\Facades\Cache;
   class UserController extends Controller{   
    /**
     * 显示给定用户的信息。
     *
     * @param  int  $id
     * @return Response
     */   
      public function showProfile($id) 
         {       
           $user = Cache::get('user:'.$id); 
           return view('profile', ['user' => $user]);  
          }
      }

Facade 和辅助函数之间没有实际的区别。当你使用辅助函数时,你可以像测试相应的 Facade 那样进行测试。例如,下面的路由:

class Cache extends Facade{   
    /**
     * 获取组件的注册名称。
     *
     * @return string
     */  
       protected static function getFacadeAccessor() { 
            return 'cache'; 
        }
     }

在底层实现,辅助函数 cache 实际是调用 Cache 这个 Facade 的 get est implémentée en bas, et la fonction auxiliaire cache appelle en fait la méthode get du Cache Façade. Par conséquent, même si nous utilisons une fonction d'assistance, nous pouvons toujours écrire le code de test suivant avec les paramètres que nous attendons pour vérifier la méthode :

<?php
   namespace App;
   use App\Contracts\Publisher;
   use Illuminate\Database\Eloquent\Model;
   class Podcast extends Model{  
     /**
     * 发布 Podcast。
     *
     * @param  Publisher  $publisher
     * @return void
     */ 
        public function publish(Publisher $publisher) 
           {     
              $this->update(['publishing' => now()]); 
              $publisher->publish($this);   
             }
        }

Comment fonctionnent les façades

Dans les applications Laravel, Facade est une classe qui peut accéder aux objets depuis le conteneur. Le composant principal est la classe Facade. Qu'il s'agisse des propres façades de Laravel ou des façades personnalisées, elles héritent toutes de la classe IlluminateSupportFacadesFacade. Facade 类。不管是 Laravel 自带的 Facades,还是自定义的 Facades,都继承自 IlluminateSupportFacadesFacade 类。

Facade 基类使用了__callStatic() 魔术方法,直到对象从容器中被解析出来后,才会进行调用。在下面的例子中,调用了 Laravel 的缓存系统。通过浏览这段代码,可以假定在 Cache 类中调用了静态方法 get

<?php
   namespace App;
   use Facades\App\Contracts\Publisher;
   use Illuminate\Database\Eloquent\Model;
   class Podcast extends Model{ 
    /**
     * 发布 Podcast。
     *
     * @return void
     */ 
        public function publish()  
          {   
               $this->update(['publishing' => now()]); 
                Publisher::publish($this);  
            }
       }

注意在上面这段代码中,我们『导入』了 Cache Facade。这个 Facade 作为访问 IlluminateContractsCacheFactory 接口底层实现的代理。我们使用 Facade 进行的任何调用都将传递给 Laravel 缓存服务的底层实例。

如果我们看一下 IlluminateSupportFacadesCache 这个类,你会发现类中根本没有 get 这个静态方法:

<?php
  namespace Tests\Feature;use App\Podcast;
  use Tests\TestCase;use Facades\App\Contracts\Publisher;
  use Illuminate\Foundation\Testing\RefreshDatabase;
  class PodcastTest extends TestCase{  
    use RefreshDatabase;   
    /**
     * 一个测试演示。
     *
     * @return void
     */  
       public function test_podcast_can_be_published()  
         {    
             $podcast = factory(Podcast::class)->create(); 
             Publisher::shouldReceive('publish')->once()->with($podcast);  
             $podcast->publish(); 
            }
      }

Cache Facade 继承了 Facade 类,并且定义了 getFacadeAccessor() 方法。这个方法的作用是返回服务容器绑定的名称。当用户调用 Cache Facade 中的任何静态方法时,Laravel 会从 服务容器 中解析 cache 绑定以及该对象运行所请求的方法(在这个例子中就是 get 方法)。

实时 Facades

使用实时 Facades,你可以将应用程序中的任何类视为 Facade。为了说明这是如何使用的,我们来看看另一种方法。例如,假设我们的 Podcast 模型有一个 publish 方法。然而,为了发布 Podcast,我们需要注入一个 Publisher 实例:

rrreee

将发布者的实现注入到该方法中,我们可以轻松地测试这种方法,因为我们可以模拟注入的发布者。但是,它要求我们每次调用 publish 方法时都要传递一个发布者实例。使用实时的 Facades,我们可以保持同样的可测试性,而不需要显式地通过 Publisher 实例。要生成实时 Facade,请在导入类的名称空间中加上 Facades:

rrreee

当使用实时 Facade 时,发布者实现将通过使用 Facades

Facade La classe de base utilise la méthode magique __callStatic(), qui ne sera appelée que lorsque l'objet sera analysé hors du conteneur. Dans l'exemple ci-dessous, le système de mise en cache de Laravel est appelé. En parcourant ce code, on peut supposer que la méthode statique get est appelée dans la classe Cache :

rrreeeNotez que dans le code ci-dessus, on "importe" < code >Cache Façade. Cette façade agit comme un proxy pour accéder à l'implémentation sous-jacente de l'interface IlluminateContractsCacheFactory. Tous les appels que nous effectuons à l'aide de Facade seront transmis à l'instance sous-jacente du service de mise en cache Laravel.

Si nous regardons la classe IlluminateSupportFacadesCache, vous constaterez qu'il n'y a pas de méthode statique get dans la classe :
rrreee
Cache Façade hérite de la classe Facade et définit la méthode getFacadeAccessor(). La fonction de cette méthode est de renvoyer le nom de la liaison du conteneur de service. Lorsque l'utilisateur appelle une méthode statique dans la façade Cache, Laravel résout la liaison cache du conteneur de service et l'objet exécute la méthode demandée (dans ce cas get ). 🎜🎜🎜🎜
🎜🎜Façades en temps réel🎜🎜En utilisant les façades en temps réel, vous pouvez ajouter n'importe quelle classe dans votre candidature Considéré comme Façade. Pour illustrer comment ceci est utilisé, regardons une autre méthode. Par exemple, supposons que notre modèle Podcast ait une méthode publish. Cependant, pour publier un podcast, nous devons injecter une instance Publisher : 🎜rrreee🎜En injectant l'implémentation de l'éditeur dans la méthode, nous pouvons facilement tester cette approche car nous pouvons nous moquer du publi injecté. Cependant, cela nous oblige à transmettre une instance d'éditeur à chaque fois que nous appelons la méthode publish. En utilisant Live Facades, nous pouvons maintenir la même testabilité sans passer explicitement une instance Publisher. Pour générer une Facade en direct, ajoutez Facades à l'espace de noms de la classe importée : 🎜rrreee🎜 Lors de l'utilisation d'une façade en direct, l'implémentation de l'éditeur apparaîtra en utilisant la partie préfixe Facades de l'interface ou du nom de classe pour résoudre le problème du conteneur de service. Lors des tests, nous pouvons utiliser la fonction d'assistance de test de façade intégrée de Laravel pour simuler cet appel de méthode : 🎜rrreee🎜🎜🎜🎜🎜🎜

Référence de classe Facade

Vous trouverez ci-dessous chaque classe Facade et sa classe sous-jacente correspondante. Il s'agit d'un outil permettant de trouver la documentation API pour une classe Facade donnée. Des informations clés sur les liaisons de conteneurs de services sont également incluses.

🎜Artisan🎜🎜IlluminateContractsConsoleKernel🎜🎜artisan🎜🎜🎜🎜Auth🎜🎜IlluminateAuthAuthManager🎜🎜auth🎜🎜🎜🎜Auth (Instance)🎜🎜IlluminateContractsAuthGuard🎜🎜auth.driver🎜🎜🎜 🎜Lame🎜🎜 IlluminateViewCompilersBladeCompiler🎜🎜blade.compiler🎜🎜🎜🎜Broadcast🎜🎜IlluminateContractsBroadcastingFactory🎜🎜 🎜🎜🎜🎜Broadcast (Instance)🎜🎜IlluminateContractsBroadcastingB roadcaster🎜🎜 🎜🎜🎜🎜Bus🎜🎜IlluminateContractsBusDispatcher🎜🎜 🎜🎜🎜🎜 Cache🎜🎜IlluminateCacheCacheManager🎜🎜cache🎜🎜🎜🎜Cache (Instance)🎜🎜IlluminateCacheRepository🎜🎜cache.store🎜🎜🎜Cookie🎜🎜IlluminateCookieCookieJar🎜🎜cookie🎜🎜🎜🎜Crypt🎜🎜Illuminate EncryptionEncrypter🎜🎜chiffreur🎜🎜🎜🎜DB🎜🎜IlluminateDatabaseDatabaseManager🎜🎜db🎜🎜🎜🎜DB (Instance)🎜🎜IlluminateDatabaseConnection🎜🎜db.connection🎜🎜🎜🎜 Événement🎜🎜 IlluminateEventsDispatcher🎜🎜événements🎜🎜🎜🎜Fichier🎜🎜IlluminateFilesystemFilesystem🎜🎜fichiers🎜🎜🎜🎜Gate🎜🎜IlluminateContractsAuthAccessGate🎜🎜 🎜🎜🎜🎜Hash🎜🎜IlluminateContractsHashingHasher🎜🎜< code>hash🎜🎜🎜🎜Lang🎜🎜IlluminateTranslationTranslator🎜🎜traducteur🎜🎜🎜🎜Log🎜🎜IlluminateLogLogManager🎜🎜log🎜🎜🎜Notification🎜🎜IlluminateNotificationsChannelManager🎜🎜 🎜🎜🎜🎜Password🎜🎜IlluminateAuth Mots de passePasswordBrokerManager🎜🎜auth.password🎜🎜🎜🎜 Mot de passe (Instance)🎜🎜IlluminateAuthPasswordsPasswordBroker🎜🎜auth.password.broker🎜🎜🎜🎜Queue🎜🎜IlluminateQueueQueueManager🎜🎜file d'attente🎜🎜🎜🎜Queue (Dans position)🎜🎜IlluminateContractsQueueQueue 🎜🎜queue.connection🎜🎜🎜🎜Queue (Classe de base)🎜🎜IlluminateQueueQueue🎜🎜 🎜🎜🎜🎜Redirect🎜🎜IlluminateRoutingRedirector🎜🎜redirect🎜 🎜🎜🎜Redis🎜 🎜IlluminateRedisRedisManager🎜🎜redis🎜🎜🎜🎜Redis (Instance)🎜🎜IlluminateRedisConnectionsConnection🎜🎜redis.connection🎜🎜🎜🎜Request🎜🎜IlluminateHttpRequest 🎜🎜demande< /code>🎜🎜SchemaIlluminateDatabaseSchemaBuilder 🎜Session🎜🎜IlluminateSessionSessionManager🎜🎜session🎜🎜🎜🎜Session (Instance)🎜🎜IlluminateSessionStore🎜🎜session.store🎜🎜🎜🎜Stor age🎜🎜IlluminateFilesystemFilesystemManager🎜🎜 système de fichiers🎜🎜🎜🎜Stockage (Instance)🎜🎜IlluminateContractsFilesystemFilesystem🎜🎜filesystem.disk🎜🎜🎜🎜URL🎜🎜IlluminateRoutingUrlGenerator🎜🎜url 🎜 🎜🎜🎜Validator🎜🎜IlluminateValidationFactory🎜🎜validator🎜🎜🎜🎜Validator (Instance)🎜🎜IlluminateValidationValidator🎜🎜 🎜🎜"View" .
FacadeClass服务容器绑定
AppIlluminateFoundationApplicationappapp
ArtisanIlluminateContractsConsoleKernelartisan
AuthIlluminateAuthAuthManagerauth
Auth (Instance)IlluminateContractsAuthGuardauth.driver
BladeIlluminateViewCompilersBladeCompilerblade.compiler
BroadcastIlluminateContractsBroadcastingFactory 
Broadcast (Instance)IlluminateContractsBroadcastingBroadcaster 
BusIlluminateContractsBusDispatcher 
CacheIlluminateCacheCacheManagercache
Cache (Instance)IlluminateCacheRepositorycache.store
ConfigIlluminateConfigRepositoryconfigconfig
CookieIlluminateCookieCookieJarcookie
CryptIlluminateEncryptionEncrypterencrypter
DBIlluminateDatabaseDatabaseManagerdb
DB (Instance)IlluminateDatabaseConnectiondb.connection
EventIlluminateEventsDispatcherevents
FileIlluminateFilesystemFilesystemfiles
GateIlluminateContractsAuthAccessGate 
HashIlluminateContractsHashingHasherhash
LangIlluminateTranslationTranslatortranslator
LogIlluminateLogLogManagerlog
MailIlluminateMailMailermailermailer
NotificationIlluminateNotificationsChannelManager 
PasswordIlluminateAuthPasswordsPasswordBrokerManagerauth.password
Password (Instance)IlluminateAuthPasswordsPasswordBrokerauth.password.broker
QueueIlluminateQueueQueueManagerqueue
Queue (Instance)IlluminateContractsQueueQueuequeue.connection
Queue (Base Class)IlluminateQueueQueue 
RedirectIlluminateRoutingRedirectorredirect
RedisIlluminateRedisRedisManagerredis
Redis (Instance)IlluminateRedisConnectionsConnectionredis.connection
RequestIlluminateHttpRequestrequest
ResponseIlluminateContractsRoutingResponseFactory 
Réponse (instance)IlluminateHttpResponse 
Route IlluminateRoutingRouterrouteurrouter
SchemaIlluminateDatabaseSchemaBuilder 
SessionIlluminateSessionSessionManagersession
Session (Instance)IlluminateSessionStoresession.store
StorageIlluminateFilesystemFilesystemManagerfilesystem
Storage (Instance)IlluminateContractsFilesystemFilesystemfilesystem.disk
URLIlluminateRoutingUrlGeneratorurl
ValidatorIlluminateValidationFactoryvalidator