php flight,php微框架 flight源码阅读——2.框架初始化、Loader、Dispatcher

宗政招
2023-12-01

在自动加载实现完成后,接着new \flight\Engine()自动加载的方式实例化了下框架的核心类Engine,这个类名翻译过来就是引擎发动机的意思,是flight的引擎发动机,很有想象力吧。

public static function app() {

static $initialized = false;

if (!$initialized) {

require_once __DIR__.'/autoload.php';

self::$engine = new \flight\Engine();

$initialized = true;

}

return self::$engine;

}

在实例化Engine这个类的时候,当前类的构造方法进行了对框架的初始化工作。

public function __construct() {

$this->vars = array();

$this->loader = new Loader();

$this->dispatcher = new Dispatcher();

$this->init();

}

接着来看init方法都做了什么,将初始化状态标记为静态变量static $initialized,判断如果为true,将$this->vars以及$this->loader、$this->dispatcher中保存的属性重置为默认状态。

static $initialized = false;

$self = $this;

if ($initialized) {

$this->vars = array();

$this->loader->reset();

$this->dispatcher->reset();

}

接下来将框架的Request、Response、Router、View类的命定空间地址register(设置)到Loader类的classes属性中。

// Register default components

$this->loader->register('request', '\flight\net\Request');

$this->loader->register('response', '\flight\net\Response');

$this->loader->register('router', '\flight\net\Router');

$this->loader->register('view', '\flight\template\View', array(), function($view) use ($self) {

$view->path = $self->get('flight.views.path');

$view->extension = $self->get('flight.views.extension');

});

flight/core/Loader.php

public function register($name, $class, array $params = array(), $callback = null) {

unset($this->instances[$name]);

$this->classes[$name] = array($class, $params, $callback);

}

再接下来就是将框架给用户提供的调用方法,设置到调度器Dispatcher类的events属性中。

// Register framework methods

$methods = array(

'start','stop','route','halt','error','notFound',

'render','redirect','etag','lastModified','json','jsonp'

);

foreach ($methods as $name) {

$this->dispatcher->set($name, array($this, '_'.$name));

}

flight/core/Dispatcher.php

/**

* Assigns a callback to an event.

*

* @param string $name Event name

* @param callback $callback Callback function

*/

public function set($name, $callback) {

$this->events[$name] = $callback;

}

接下来呢,就是设置框架的一些配置,将这些配置保存在Engine类的vars属性中。

// Default configuration settings

$this->set('flight.base_url', null);

$this->set('flight.case_sensitive', false);

$this->set('flight.handle_errors', true);

$this->set('flight.log_errors', false);

$this->set('flight.views.path', './views');

$this->set('flight.views.extension', '.php');

flight/Engine.php

/**

* Sets a variable.

*

* @param mixed $key Key

* @param string $value Value

*/

public function set($key, $value = null) {

if (is_array($key) || is_object($key)) {

foreach ($key as $k => $v) {

$this->vars[$k] = $v;

}

}

else {

$this->vars[$key] = $value;

}

}

最后一步的操作,当调用框架的start方法时,给其设置一些前置操作,通过set_error_handler()和set_exception_handler()设置用户自定义的错误和异常处理函数,如何使用自定义的错误和异常函数,可以看这两个范例:https://segmentfault.com/n/13...

https://segmentfault.com/n/13...。

// Startup configuration

$this->before('start', function() use ($self) {

// Enable error handling

if ($self->get('flight.handle_errors')) {

set_error_handler(array($self, 'handleError'));

set_exception_handler(array($self, 'handleException'));

}

// Set case-sensitivity

$self->router()->case_sensitive = $self->get('flight.case_sensitive');

});

$initialized = true;

/**

* Custom error handler. Converts errors into exceptions.

*

* @param int $errno Error number

* @param int $errstr Error string

* @param int $errfile Error file name

* @param int $errline Error file line number

* @throws \ErrorException

*/

public function handleError($errno, $errstr, $errfile, $errline) {

if ($errno & error_reporting()) {

throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);

}

}

/**

* Custom exception handler. Logs exceptions.

*

* @param \Exception $e Thrown exception

*/

public function handleException($e) {

if ($this->get('flight.log_errors')) {

error_log($e->getMessage());

}

$this->error($e);

}

当调用$self->router()时,会触发当前类的__call()魔术方法,通过$this->loader->get($name)判断属性$classes中router索引是否存在,不存在抛出异常,存在就通过$this->loader->load($name, $shared)去实例化初始化时设置的'\flight\net\Router',这里是工厂模式,接下来的路由文章会详细分析。

/**

* Handles calls to class methods.

*

* @param string $name Method name

* @param array $params Method parameters

* @return mixed Callback results

* @throws \Exception

*/

public function __call($name, $params) {

$callback = $this->dispatcher->get($name);

if (is_callable($callback)) {

return $this->dispatcher->run($name, $params);

}

if (!$this->loader->get($name)) {

throw new \Exception("{$name} must be a mapped method.");

}

$shared = (!empty($params)) ? (bool)$params[0] : true;

return $this->loader->load($name, $shared);

}

在$this->before()操作中,会将前置操作设置到Dispatcher类的filters属性中。这些操作完成后,将$initialized = true。

/**

* Adds a pre-filter to a method.

*

* @param string $name Method name

* @param callback $callback Callback function

*/

public function before($name, $callback) {

$this->dispatcher->hook($name, 'before', $callback);

}

flight/core/Dispatcher.php

/**

* Hooks a callback to an event.

*

* @param string $name Event name

* @param string $type Filter type

* @param callback $callback Callback function

*/

public function hook($name, $type, $callback) {

$this->filters[$name][$type][] = $callback;

}

 类似资料: