醜話說在前面,這一章難點,但也算是框架的核心了,你們靜下心學吧。
看一個概念分發器
,英文叫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
的區別在因而否保存子類實例
下期見