php 如何实现简单的 Facades?

<?php

# model.php

namespace Model\TestModel;

class User
{
    public function get()
    {
        return '爱因斯坦';
    }
}

<?php

# run.php

use Model\TestModel\User;

require __DIR__ . '/model.php';

$user = new User();
echo $user->get();

我想实现像 Laravel Facades 一样的用法,load.php怎么写?

<?php

# run.php

require __DIR__ . '/load.php';

echo \User::get();
阅读 3.6k
2 个回答

参考:Laravel Facade 原理学习

<?php

# load.php

require_once __DIR__ . '/model.php';

class User extends Facade
{
    protected static function getFacadeAccessor()
    {
        $instanceKey = 'user';
        // 单例
        if (!isset(self::$resolvedInstance[$instanceKey])) {
            $user = new Model\TestModel\User();
            self::$resolvedInstance[$instanceKey] = $user;
        }
        return $instanceKey;
    }
}

/**
 * A simple Facade Class, From Illuminate\Support\Facades\Facade
 */
abstract class Facade
{
    /**
     * The resolved object instances.
     *
     * @var array
     */
    protected static $resolvedInstance;

    /**
     * Get the registered name of the component.
     *
     * @return string
     *
     * @throws \RuntimeException
     */
    protected static function getFacadeAccessor()
    {
        throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
    }

    /**
     * Handle dynamic, static calls to the object.
     *
     * @param  string  $method
     * @param  array   $args
     * @return mixed
     *
     * @throws \RuntimeException
     */
    public static function __callStatic($method, $args)
    {
        $instanceKey = static::getFacadeAccessor();
        $instance = self::$resolvedInstance[$instanceKey];

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        return $instance->$method(...$args);
    }
}

你需要自行实现一个Facade对象,把所有的方法调用代理到真实的对象。

class UserFacade
{
    private $user;

    public function __constructor()
    {
        $this->user = new User();
    }

    public function __callStatic($name, $arguments)
    {
        return call_user_func_array(array($this, $name), $arguments);
    }
}
$user UserFacade::get();

任何对UserFacade的静态方法调用都会代理到User。__callStatic在有静态调用的时候触发,传入的参数$name是UserFacade::get静态调用的方法名,$arguments是参数的数组。

Laravel官方描述Facade是简洁的、容易记忆的类调用,Laravel的特性基本都提供Facade类。在业务开发这个层面,我不推荐静态类调用的设计方式,这个我另外开个帖子讨论。

参考

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题