丑话说在前面,这一章难点,但也算是框架的核心了,你们静下心学吧。
看一个概念分发器
,英文叫dispather
,它的主要做用是管理全部类的实例化操做。在程序中,有时须要大量建立对象实例,有时须要使用相同的实例,所以若是重复建立实例会额外给程序带来开销和管理的负担。因此咱们使用了分发器的概念,用于专门管理全部类的实例化操做。以前,咱们都是经过 new
关键字建立对象,如入口文件的 new Application()
,以及 Application
类的构造器中 new Bootstrap()
。若是有分发器就简单多了。php
在 core
目录下建立目录 dispatcher
,并建立文件 Dispatcher.php,Container.php,Box.phphtml
$ cd origin/core $ mkdir dispatcher $ cd dispatcher $ touch Dispatcher.php Container.php Box.php
Dispatcher 是一个抽象类,定义了一个抽象方法 getInstance()
,用于获取子类实例。子类 Container 和 Box 分别继承 Dispatcher 并实现 getInstance()
方法,不一样点在于,容器中该方法须要存放子类实例,盒子中直接进行实例化操做。linux
容器就是存东西的变量 在这里咱们存放全部调用类的实例,固然也能够存服务,接口取决于你 everything框架
Dispatcher
类主要实现:函数
getInstance()
abstract function getInstance();
注意抽象方法必须使用关键字 abstract
声明,而且不能包含函数体(中括号包括的部分)ui
__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')
。spa
1,第一行 static::getInstance();
执行子类的 getInstance()
方法,所以须要在 Container
和 Box
中分别实现该方法。code
2,经过 call_user_func_array()
调用自身存在的方法,该方法须要声明为 protected
htm
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
类继承 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()
获取调用类的名称。
和 Container
类同样,Box
继承 Dispatcher
,同时实现 getInstance()
方法
编辑 Box.php
<?php namespace dispatcher; class Box extends Dispatcher { /** * 该类的子类都会从新实例化 * */ public function getInstance() { return self::newObject(); } }
Container
或 Box
类。::
符号后面直接接的方法必须声明为 protected
。register()
方法获取类实例。一个简单的例子
<?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 完。
没搞懂的,看看这篇文章吧 http://www.javashuo.com/article/p-tfvtgghu-ht.html
本结主要介绍了分发器的概念,实现了一个简单的类管理机制,能够经过静态方式调用对象方法。分发器类 Container
和 Box
的区别在因而否保存子类实例
下期见