php微框架 flight源碼閱讀——1.自動加載

先來看下框架的單入口文件index.php,先引入了Flight.php框架類文件。php

<?php
require 'flight/Flight.php';
Flight::route('/', function(){
    echo 'hello world!';
});
Flight::start();

Flight.php中定義了Flight類,類裏面先定義了3個魔術方法,這三個魔術方法是爲了防止當前類被實例化segmentfault

// Don't allow object instantiation
private function __construct() {}
private function __destruct() {}
private function __clone() {}

若是試着去new Flight會提示以下錯誤:數組

Fatal error: Uncaught Error: Call to private Flight::__construct() from invalid context in /usr/local/var/www/flight135/index.php:3 Stack trace: #0 {main} Next Error: Call to private Flight::__destruct() from context '' in /usr/local/var/www/flight135/index.php:3 Stack trace: #0 {main} thrown in /usr/local/var/www/flight135/index.php on line 3

接着定義了一個重載方法__callStatic(),在index.php中執行Flight::route('/', 'hello')就會調用該__callStatic,其中$name就是'route'$params就是本身寫的hello函數。在__callStatic()中調用了當前類的app()靜態方法,這裏爲何不使用self::app()來調用呢?php框架

/**
 * Handles calls to static methods.
 *
 * @param string $name Method name
 * @param array $params Method parameters
 * @return mixed Callback results
 * @throws \Exception
 */
public static function __callStatic($name, $params) {
    $app = Flight::app();
    return \flight\core\Dispatcher::invokeMethod(array($app, $name), $params);
}

接着就是在static app()中開始處理自動加載了app

/**
 * @return \flight\Engine Application instance
 */
public static function app() {
    static $initialized = false;
    if (!$initialized) {
        require_once __DIR__.'/autoload.php';
        self::$engine = new \flight\Engine();
        $initialized = true;
    }
    return self::$engine;
}

進入到autoload.php來看,引入了core目錄下的Loader.php類文件,Loader就是加載器。框架

autoload.php
require_once __DIR__.'/core/Loader.php';
\flight\core\Loader::autoload(true, dirname(__DIR__));

Loader中定義了加載存放哪些類型:$classes(類路徑數組),$instances(對象數組),$dirs(框架目錄路徑數組)函數

/**
 * Registered classes.
 *
 * @var array
 */
protected $classes = array();
/**
 * Class instances.
 *
 * @var array
 */
protected $instances = array();
/**
 * Autoload directories.
 *
 * @var array
 */
protected static $dirs = array();

autoload()中使用spl_autoload_register將當前類(__CLASS__)中的loadClass方法註冊爲加載的執行方法。測試

/**
 * Starts/stops autoloader.
 *
 * @param bool $enabled Enable/disable autoloading
 * @param array $dirs Autoload directories
 */
public static function autoload($enabled = true, $dirs = array()) {
    if ($enabled) {
        spl_autoload_register(array(__CLASS__, 'loadClass'));
    }
    else {
        spl_autoload_unregister(array(__CLASS__, 'loadClass'));
    }
    if (!empty($dirs)) {
        self::addDirectory($dirs);
    }
}

/**
 * Autoloads classes.
 *
 * @param string $class Class name
 */
public static function loadClass($class) {
    $class_file = str_replace(array('\\', '_'), '/', $class).'.php';
    foreach (self::$dirs as $dir) {
        $file = $dir.'/'.$class_file;
        if (file_exists($file)) {
            require $file;
            return;
        }
    }
}

接下來咱們試着按照flight自動加載的方式,寫個簡單的自動加載進行測試:ui


/autoload/index.phpspa

<?php
class MyClass{
    public static function __callStatic($name, $params){
        self::app();
    }

    public static function app(){
        require_once __DIR__.'/Loader.php';
        Loader::autoload(true, dirname(__DIR__));

        new \autoload\Test();
    }
}

MyClass::test();
new \autoload\Test2();
var_dump(Loader::getClasses());//array(2) { [0]=> string(36) "/usr/local/var/www/autoload/Test.php" [1]=> string(37) "/usr/local/var/www/autoload/Test2.php" }

/autoload/Loader.php

<?php
class Loader {
    public static $dirs = [];
    public static $classes = [];

    public static function autoload($enabled=true, $dirs=[]) {
        if ($enabled) {
            spl_autoload_register([__CLASS__, 'loadClass']);
        } else {
            spl_autoload_unregister([__CLASS__, 'loadClass']);
        }
        
        if (!empty($dirs)) {
            self::addDirectory($dirs);
        }
    }

    public static function loadClass($class) {
        $class_file = str_replace(['\\', '_'], '/', $class).'.php';
        
        foreach (self::$dirs as $dir) {
            $file = $dir.'/'.$class_file;
            
            if (file_exists($file)) {
                require $file;
                self::$classes[] = $file;
                
                return;
            }
        }
    }

    public static function addDirectory($dir) {
        if (is_array($dir) || is_object($dir)) {
            foreach ($dir as $value) {
                self::addDirectory($value);
            }
        }
        else if (is_string($dir)) {
            if (!in_array($dir, self::$dirs)) self::$dirs[] = $dir;
        }
    }

    public static function getClasses(){
        return self::$classes;
    }
}

/autoload/Test.php

<?php
namespace autoload;
class Test {}

/autoload/Test2.php

<?php
namespace autoload;
class Test2 {}

php微框架 flight源碼閱讀系列

相關文章
相關標籤/搜索