Que sont les conteneurs et les façades ? Une brève analyse des conteneurs et des façades dans thinkphp5.1

不言
Libérer: 2023-04-03 17:58:01
original
4381 Les gens l'ont consulté

Cet article vous explique qu'est-ce qu'un conteneur (Container) et une façade (Facade) ? La brève analyse des conteneurs et des façades dans thinkphp5.1 a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer, j'espère qu'elle vous sera utile.

P5.1 a introduit deux nouvelles classes, conteneur (Container) et façade (Facade)

Le document officiel a donné la définition :

Conteneur (Container) pour obtenir un résultat unifié. gestion des classes et garantir l’unicité des instances d’objets.

Facade fournit une interface d'appel statique pour les classes du conteneur (Container). Par rapport à l'appel de méthode statique traditionnelle, elle apporte une meilleure testabilité et évolutivité. Vous pouvez définir une classe de façade.

En approfondissant le code source, examinons comment il est implémenté :

// 在框架目录下的base.php文件

// 注册核心类到容器
Container::getInstance()->bind([
    'app'                   => App::class,
    'build'                 => Build::class,
    'cache'                 => Cache::class,
    'config'                => Config::class,
    ...
]);

// 注册核心类的静态代理
Facade::bind([
    facade\App::class      => App::class,
    facade\Build::class    => Build::class,
    facade\Cache::class    => Cache::class,
    facade\Config::class   => Config::class,
    ...
]);

// 注册类库别名
Loader::addClassAlias([
    'App'      => facade\App::class,
    'Build'    => facade\Build::class,
    'Cache'    => facade\Cache::class,
    'Config'   => facade\Config::class,
    ...
]);
Copier après la connexion

Implémentation du conteneur :

Ici, le framework nous a aidé à lier le système commun classes dans le conteneur. Lorsque vous l'utiliserez plus tard, il vous suffit d'appeler la fonction d'assistance app() pour effectuer l'analyse de classe dans le conteneur. L'identifiant de classe lié sera automatiquement et rapidement instancié.

// 实例化缓存类

app('cache'); 
// app('cache', ['file']); 参数化调用

// 相当于执行了
Container::get('cache');

// 查看源码,Container调用的其实是make方法,在该方法里调用反射等实现类的实例化,过程如下:
Copier après la connexion
public function make($abstract, $vars = [], $newInstance = false)
{
    if (true === $vars) {
        // 总是创建新的实例化对象
        $newInstance = true;
        $vars        = [];
    }

    if (isset($this->instances[$abstract]) && !$newInstance) {
        $object = $this->instances[$abstract];
    } else {
        if (isset($this->bind[$abstract])) {
            $concrete = $this->bind[$abstract];
       // 闭包实现
            if ($concrete instanceof \Closure) {
                $object = $this->invokeFunction($concrete, $vars);
            } else {
                $object = $this->make($concrete, $vars, $newInstance);
            }
        } else {
       // 反射实现
            $object = $this->invokeClass($abstract, $vars);
        }

        if (!$newInstance) {
            $this->instances[$abstract] = $object;
        }
    }

    return $object;
}
Copier après la connexion
/**
 * 调用反射执行类的实例化 支持依赖注入
 * @access public
 * @param  string    $class 类名
 * @param  array     $vars  变量
 * @return mixed
 */
public function invokeClass($class, $vars = [])
{
    $reflect     = new \ReflectionClass($class);
    $constructor = $reflect->getConstructor();

    if ($constructor) {
        $args = $this->bindParams($constructor, $vars);
    } else {
        $args = [];
    }

    return $reflect->newInstanceArgs($args);
}
Copier après la connexion
/**
 * 执行函数或者闭包方法 支持参数调用
 * @access public
 * @param  string|array|\Closure $function 函数或者闭包
 * @param  array                 $vars     变量
 * @return mixed
 */
public function invokeFunction($function, $vars = [])
{
    $reflect = new \ReflectionFunction($function);
    $args    = $this->bindParams($reflect, $vars);

    return $reflect->invokeArgs($args);
}
Copier après la connexion

En bref, l'instanciation des classes est implémentée à l'intérieur du conteneur via des classes de réflexion ou des fermetures.

Mise en œuvre de la façade :

Analysons-la avec un exemple :

facade\Config::get('app_debug');
Copier après la connexion

Analysons sa mise en œuvre :

// thinkphp\library\facade\Config 类
Copier après la connexion
namespace think\facade;

use think\Facade;

class Config extends Facade
{
}
Copier après la connexion

// D'après le code source, Config lui-même n'a aucune méthode. Il hérite des méthodes de Facade, mais Facade n'a pas la méthode statique de get
// A ce moment, le système déclenche automatiquement la méthode magique : __callStatic() , Facade a réécrit cette méthode :

public static function __callStatic($method, $params)
{
    return call_user_func_array([static::createFacade(), $method], $params);
}
Copier après la connexion

// On voit que le dernier appel est la fonction définie par l'utilisateur : call_user_func_array([instance, méthode], paramètre). Instance de configuration, Facade définit un objet d'acquisition Méthode :

/**
 * 创建Facade实例
 * @static
 * @access protected
 * @param  string    $class          类名或标识
 * @param  array     $args           变量
 * @param  bool      $newInstance    是否每次创建新的实例
 * @return object
 */
protected static function createFacade($class = '', $args = [], $newInstance = false)
{
    $class       = $class ?: static::class;
    $facadeClass = static::getFacadeClass();

    if ($facadeClass) {
        $class = $facadeClass;
    } elseif (isset(self::$bind[$class])) {
        $class = self::$bind[$class];
    }

    if (static::$alwaysNewInstance) {
        $newInstance = true;
    }

    return Container::getInstance()->make($class, $args, $newInstance);
}
Copier après la connexion

// En interne, l'objet est instancié via le conteneur
// Parce que la classe thinkConfig a été liée à l'identifiant de configuration dans base.php

Container::getInstance()->bind([
  'config'  => Config::class
])

// 在 createFacade 方法中,获取类的名称:$class = $class ?: static::class; 即得到 config 这个标识
Copier après la connexion
// 在容器的make方法中,根据config标识,找到绑定的 think\Config 类,并调用其动态方法 get。

facade\Config::get('app_debug'); 

// 最后调用的是:

(new think\Config())->get('app_debug');
Copier après la connexion

En bref, la façade est implémentée via la méthode magique de PHP __callStatic, puis coopère avec le conteneur pour réaliser des appels statiques de classes dynamiques.

Recommandations associées :

Comment juger si le modèle thinkphp est un paiement mobile WeChat ou un paiement par scan code WeChat

PHP veut réaliser saut de page Comment fonctionne la fonction ? (Exemple de balise de fonction)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!