PHP 手寫MVC(二) —— 自動加載和Bootstrap

類自動加載:

在使用類的時候會用 requireinclude 將類加載進來,可是每次都手動加載,會致使一系列問題,好比類重複加載,管理困難等。因此解決上述問題,咱們使用單獨的一個文件來完成全部類的自動加載。php

spl_autoload_register()

該函數能夠註冊任意數量的自動加載器,當使用還沒有被定義的類(class)和接口(interface)時自動去加載。經過註冊自動加載器,腳本引擎在 PHP 出錯失敗前有了最後一個機會加載所需的類。html

儘管 __autoload() 函數也能自動加載類和接口,但更建議使用 spl_autoload_register() 函數。 spl_autoload_register() 提供了一種更加靈活的方式來實現類的自動加載(同一個應用中,能夠支持任意數量的加載器,好比第三方庫中的)。所以,再也不建議使用 __autoload() 函數,在之後的版本中它可能被棄用。

core 目錄下建立一個 Autoload.php 文件linux

$ cd tinyphp/core
$ touch Autoload.php

編輯 Autoload.php瀏覽器

// 命名空間和文件目錄映射
<?php
$path = [
    'core' => 'core',
    'app' => 'app',
    'controller' => 'app/controllers',
    'model' => 'app/models',
    'view' => 'app/views',
    'dispatcher' => 'core/dispatcher',
];

/**
 * 參數 $class 表示自動加載的類名
 * 
 * 匿名函數中使用 use 可使用外部變量
 */
spl_autoload_register(function($class) use ($path) {

    //解析類名,若是使用了命名空間,則會查找 $path 中對於的路徑
    $position = strripos($class,'\\');

    $key = substr($class,0,$position);
    $value = $path[$key] ?? '';

    $file = substr($class,$position+1).'.php';

    require APP_PATH.'/'.$value.'/'.$file;
});

spl_autoload_register() 主要實現類自動加載,參數使用的是匿名函數,經過關鍵字 use 可使用外部變量 $path,其做用是提供命名空間和路徑的對應關係,例如使用 namespace controller,對應的類在路徑 app/controllers服務器

使用方式爲,在入口文件public/index.php 中,直接 require 該文件便可。app

<?php

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

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

而後咱們在core 文件夾下建立一個名爲 Application.php 並編輯內容框架

<?php

namespace core;

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

自動加載完成,待會啓動(註冊)框架以後就能夠看到效果了。函數

註冊啓動項

有時候須要在框架啓動時,額外加載一些應用配置或用戶定義的方法,好比定義常量,加載自定義輔助函數等。ui

咱們在應用目錄 app 中建立一個啓動腳本 Bootstrap.php,規定該腳本內全部以 init 的方法都會被調用,並在 Application 類的構造函數中調用該腳本this

建立 app/Bootstrap.php,編輯內容

<?php 

namespace app;

class Bootstrap
{
    /**
     * 全部以 init 開始的函數都會被依次調用
     *
     */
    public function initConst()
    {
        echo 'Bootstrap : 1'.PHP_EOL;
    }
    
    public function initHelper()
    {
        echo 'Bootstrap : 2'.PHP_EOL;
    }
}

Application 類中添加啓動項

  • 在構造函數 __construct() 中獲取 Bootstrap 實例。
  • run() 方法中遍歷 Bootstrap 類中以 init 開頭的方法並執行。
<?php
//這裏用...省略以前的代碼,在實際操做中,須要完整的代碼,否則會報錯
...
    public $boot;
    
    public function __construct()
    {
        /**
         * \app\爲命名空間,
         * 第一個\表示在根目錄,否在表示在當前命名空間下的子目錄
         * 
         * 例如,app\Bootstrap() 表示在類在 tinyphp/core/app 目錄下
         * \app\Bootstrap() 則表示在 tinyphp/app 目錄下
         */
        $this->boot = new \app\Bootstrap();
    }
    public function run()
    {
        /**
         * 執行啓動項
         * 全部init開頭的方法都會被調用
         *
         */
        foreach(get_class_methods($this->boot) as $func) {
            if (0 === strpos($func, 'init')) {
                call_user_func([$this->boot,$func]);
            }
        }
    }
...

啓動框架

在入口文件 index.php 中啓動框架,並執行 run() 方法

<?php

use \core\Application;

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

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

(new Application())->run();

進入 public 目錄,兩種方式執行 php

  • 命令行
$ php index.php
Bootstrap : 1
Bootstrap : 2
  • 使用 PHP 內置服務器
$ php -S localhost:8080

在瀏覽器輸入 http://localhost:8080 , 結果以下

Bootstrap : 1Bootstrap : 2

從結果能夠看出,Application 類在實例化的時候執行構造函數,構造函數中完成了啓動項的方法調用。

3、總結

本節實現了一個簡單的類自動加載和框架的核心類,在啓動時加載用戶啓動項,在 app/Bootstrap.php 中全部以 init 開頭的方法都會被依次調用。

下期見

相關文章
相關標籤/搜索