先來看下框架的單入口文件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 {}