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

丑话说在前面,这一章难点,但也算是框架的核心了,大家静下心学吧。

分发器

看一个概念分发器,英文叫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() 方法,不同点在于,容器中该方法需要存放子类实例,盒子中直接进行实例化操作。

容器 Container。容器中的实例可以重复使用

盒子 Box。盒子中的实例不能重复使用,每次会创建新的实例

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

Dispatcher 类

Dispatcher 类主要实现:

定义抽象方法 getInstance()

abstract function getInstance();

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

接收所有静态方式请求__callStatic()

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() 方法,因此需要在 Container 和 Box 中分别实现该方法。

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

使用延迟静态绑定实例化子类

public static function newObject()

{

return new Static;

}

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

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

定义获取类实例函数 register()

public static function register()

{

return static::getInstance();

}

该函数获取子类实例。

Container 类

Container 类继承 Dispatcher,同时实现 getInstance() 方法。

该类使用一个静态变量 $container 来保存所有类实例,当再次调用该实例时直接返回,无需在实例化操作。

编辑 Container.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

namespace dispatcher;

class Box extends Dispatcher

{

/**

* 该类的子类都会重新实例化

*

*/

public function getInstance()

{

return self::newObject();

}

}

使用分发器

使用规则

一个类要使用分发器,必须继承 Container 或 Box 类。

类方法通过静态方式调用,同时::符号后面直接接的方法必须声明为 protected。

通过 register() 方法获取类实例。

一个简单的例子

use core\Application;

// error_reporting(0);

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

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

(Application::register())::dispatcher();

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 完。

关于延迟静态绑定

总结

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

下期见

作者:entner

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值