PHP手写MVC(三) —— 分发器

in 网站建设
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
丑话说在前面,这一章难点,但也算是框架的核心了,大家静下心学吧。

分发器

看一个概念分发器,英文叫dispather,它的主要作用是管理所有类的实例化操作。在程序中,有时需要大量创建对象实例,有时需要使用相同的实例,因此如果重复创建实例会额外给程序带来开销和管理的负担。所以我们使用了分发器的概念,用于专门管理所有类的实例化操作。之前,我们都是通过 new 关键字创建对象,如入口文件的 new Application(),以及 Application 类的构造器中 new Bootstrap()。如果有分发器就简单多了。

core 目录下创建目录 dispatcher,并创建文件 Dispatcher.php,Container.php,Box.php

$ cd origin/core
$ mkdir dispatcher
$ cd dispatcher
$ touch Dispatcher.php Container.php Box.php

Dispatcher 是一个抽象类,定义了一个抽象方法 getInstance(),用于获取子类实例。子类 Container 和 Box 分别继承 Dispatcher 并实现 getInstance() 方法,不同点在于,容器中该方法需要存放子类实例,盒子中直接进行实例化操作。

容器就是存东西的变量 在这里我们存放所有调用类的实例,当然也可以存服务,接口取决于你 everything

Dispatcher 类

Dispatcher 类主要实现:

abstract function getInstance();

注意抽象方法必须使用关键字 abstract 声明,并且不能包含函数体(中括号包括的部分)

public static function __callstatic(string $method, array $args)
{
    //1
    $instance = static::getInstance();
    //2
    return call_user_func_array(array($instance, $method), $args);
}

__callstatic 该方法的作用是,你在其他文件调用的不可见的静态方法都会执行该方法,所以它也是分发器入口。所有通过静态方式调用的不可见的类方法都会执行该函数,如 Config::get('db')

1,第一行 static::getInstance(); 执行子类的 getInstance() 方法,因此需要在 ContainerBox 中分别实现该方法。

2,通过 call_user_func_array() 调用自身存在的方法,该方法需要声明为 protected

public static function newObject()
{
    return new Static;
}

该函数的作用是实例化操作,在子类 ContainerBox 中调用,new Static 返回创建具体执行操作的该子类实例,如 Config::get() 那么返回 Config 类的实例,Router::start() 返回 Router 类的实例。

关于延迟静态绑定 很重要 我下面会继续讲 请耐心看

public static function register()
{
    return static::getInstance();
}

该函数获取子类实例。

Container 类

Container 类继承 Dispatcher,同时实现 getInstance() 方法。
该类使用一个静态变量 $container 来保存所有类实例,当再次调用该实例时直接返回,无需在实例化操作。

编辑 Container.php

<?php

namespace dispatcher;

/**
 * 继承 Dispatcher 必须实现 getInstance() 方法
 *
 */
class Container extends Dispatcher
{
    //存储子类实例
    public static $container = [];

    /**
     * 实现父类抽象方法
     *
     * 如果容器中已存在子类实例,直接返回
     */
    public function getInstance()
    {
        //获取子类名称
        $class = get_called_class();

        if (!isset(self::$container[$class]) ||
                !self::$container[$class] instanceof $class) {

            self::$container[$class] = self::newObject();
        }
        return self::$container[$class];
    }
}

get_called_class() 获取调用类的名称。

Box 类

Container 类一样,Box 继承 Dispatcher,同时实现 getInstance() 方法

编辑 Box.php

<?php

namespace dispatcher;

class Box extends Dispatcher
{
    /**
     * 该类的子类都会重新实例化
     *
     */
    public function getInstance()
    {
        return self::newObject();
    }
}

使用分发器

使用规则

一个简单的例子

<?php

use core\Application;

// error_reporting(0);

define('APP_PATH',dirname(__DIR__));

require APP_PATH.'/core/Autoload.php';

(Application::register())::dispatcher();
<?php

namespace core;

use dispatcher\Container;

class Application extends Container
{
    public function run()
    {
        echo 'hello world';
    }

    protected function dispatcher()
    {
        echo 'dispatcher';
    }

  
}

可以通过 Application::dispatcher(); 调用类方法(非静态方法)。通过 Application::register(); 可以获取 Application 类实例。

执行 index.php 会输出 dispatcher

理理思路

1.先不管分发器怎么实现的,当你使用时必须得 use 吧
2.当我们从 index 出发,去调用了一个 静态的 dispatcher 方法时,Application 本身没有这样一个静态的方法啊,怎么办? 只能通过自动加载到 container.php 这个文件了,还是没找到这个方法,怎么办? container 继承了 Dispatcher,好了 有 __callStatic ,这时候会自动进入这个函数,接下来,请注意,这里利用了 static 这个关键字来延迟绑定(呼应上文),简单来说,就是哪个类触发的 callStatic,static 就代表哪个类,如果你换成self 就会报错,好了接着说,调用类,这里是 Application紧接着调用了 dispatcher 子类的getInstance 方法去获得了该类的实例,最后回调,输出 dispatcher 完。

关于延迟静态绑定

没搞懂的,看看这篇文章吧 https://www.cnblogs.com/codeAB/p/5560631.html

总结

本结主要介绍了分发器的概念,实现了一个简单的类管理机制,可以通过静态方式调用对象方法。分发器类 ContainerBox 的区别在于是否保存子类实例

下期见

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看