What is the Facade in TP

Posted by Daggeth on Thu, 24 Oct 2019 06:24:16 +0200

What is the Facade in TP? At present, it is a class that is used to facilitate the static way to call the corresponding method to implement the original class (undefined static method).
The specific implementation of Facade is as follows:
First look at the core document:
\thinkphp\base.php
`//Register static proxy of core class
Facade::bind([

facade\App::class      => App::class,
facade\Build::class    => Build::class,
facade\Cache::class    => Cache::class,
facade\Config::class   => Config::class,
facade\Cookie::class   => Cookie::class,
facade\Debug::class    => Debug::class,
facade\Env::class      => Env::class,
facade\Hook::class     => Hook::class,
facade\Lang::class     => Lang::class,
facade\Log::class      => Log::class,
facade\Request::class  => Request::class,
facade\Response::class => Response::class,
facade\Route::class    => Route::class,
facade\Session::class  => Session::class,
facade\Url::class      => Url::class,
facade\Validate::class => Validate::class,
facade\View::class     => View::class,]);

You can see the binding method similar to that in the container. Find the corresponding binding method as follows:

` /**

 * Static proxy of binding class
 * @static
 * @access public
 * @param  string|array  $name    Class ID
 * @param  string        $class   Class name
 * @return object
 */
public static function bind($name, $class = null)
{
    if (__CLASS__ != static::class) {
        return self::__callStatic('bind', func_get_args());
    }

    if (is_array($name)) {
        self::$bind = array_merge(self::$bind, $name);
    } else {
        self::$bind[$name] = $class;
    }
}`
//You can see that it is also put into an array $bind.

Here, notice the following method of registering class alias in thinkphpbase.php file, which can realize class alias direct access to class (see here for yourself)
`//Register class library alias
Loader::addClassAlias([

'App'      => facade\App::class,
'Build'    => facade\Build::class,
'Cache'    => facade\Cache::class,
'Config'   => facade\Config::class,
'Cookie'   => facade\Cookie::class,
'Db'       => Db::class,
'Debug'    => facade\Debug::class,
'Env'      => facade\Env::class,
'Facade'   => Facade::class,
'Hook'     => facade\Hook::class,
'Lang'     => facade\Lang::class,
'Log'      => facade\Log::class,
'Request'  => facade\Request::class,
'Response' => facade\Response::class,
'Route'    => facade\Route::class,
'Session'  => facade\Session::class,
'Url'      => facade\Url::class,
'Validate' => facade\Validate::class,
'View'     => facade\View::class,]);

How to call static methods, such as

\Cache::set('name','value');

For this method, how to call the set method at a specific time? First, use the alias mechanism of the above class to find the corresponding facade cache:: class, which is actually called. Then let's look at the contents of this class:

namespace think\facade;

use think\Facade;

class Cache extends Facade
{
}

You can see that there is no content, so where is the set method? Here we use a method that will be called if the static method call of PHP fails. In the Facade class, there are:

 // Call the method of the actual class
    public static function __callStatic($method, $params)
    {
        return call_user_func_array([static::createFacade(), $method], $params);
    }
//When an invocation method is invoked in a static context, __callStatic() is called.    

In other words, when the set method is not called, the method will be called, that is, it is actually called.

call_user_func_array([static::createFacade(), $method], $params)

In fact:

/**
     * Create a Facade instance
     * @static
     * @access protected
     * @param  string    $class          Class name or ID
     * @param  array     $args           variable
     * @param  bool      $newInstance    Whether to create a new instance every time
     * @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);
    }

You can see the last sentence, which is actually the set method of the instance of Cache::class (obtained through the container).

Topics: PHP Session