defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev'); require(__DIR__ . '/../vendor/autoload.php'); // 注册 Composer 加载器 Yii::setAlias('@common', dirname(__DIR__)); // 注册别名
{
\yii\BaseYii::setAlias($alias, $path)
{
if (strncmp($alias, '@', 1)) {
$alias = '@' . $alias;
}
$pos = strpos($alias, '/');
$root = $pos === false ? $alias : substr($alias, 0, $pos);
if ($path !== null) {
$path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
if (!isset(static::$aliases[$root])) {
if ($pos === false) {
static::$aliases[$root] = $path;
} else {
static::$aliases[$root] = [$alias => $path];
}
} elseif (is_string(static::$aliases[$root])) {
if ($pos === false) {
static::$aliases[$root] = $path;
} else {
static::$aliases[$root] = [
$alias => $path,
$root => static::$aliases[$root],
];
}
} else {
static::$aliases[$root][$alias] = $path;
krsort(static::$aliases[$root]);
}
} elseif (isset(static::$aliases[$root])) {
if (is_array(static::$aliases[$root])) {
unset(static::$aliases[$root][$alias]);
} elseif ($pos === false) {
unset(static::$aliases[$root]);
}
}
}
} require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
{
class Yii extends \yii\BaseYii
{
} spl_autoload_register(['Yii', 'autoload'], true, true); // 注册类加载器
\yii\BaseYii::autoload($className)
{
if (isset(static::$classMap[$className])) { // 查找 $classMap 映射
$classFile = static::$classMap[$className];
if ($classFile[0] === '@') {
$classFile = static::getAlias($classFile);
}
} elseif (strpos($className, '\\') !== false) {
$classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false); // 通过别名获取
{
\yii\BaseYii::getAlias($alias, $throwException = true)
{
if (strncmp($alias, '@', 1)) {
// not an alias
return $alias;
} $pos = strpos($alias, '/');
$root = $pos === false ? $alias : substr($alias, 0, $pos);
if (isset(static::$aliases[$root])) {
if (is_string(static::$aliases[$root])) {
return $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos);
} foreach (static::$aliases[$root] as $name => $path) {
if (strpos($alias . '/', $name . '/') === 0) {
return $path . substr($alias, strlen($name));
}
}
} if ($throwException) {
throw new InvalidParamException("Invalid path alias: $alias");
} return false;
}
}
if ($classFile === false || !is_file($classFile)) {
return;
}
} else {
return;
} include($classFile); // 加载类 if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) {
throw new UnknownClassException("Unable to find '$className' in file: $classFile. Namespace missing?");
}
}
Yii::$classMap = require(__DIR__ . '/classes.php'); // 内置类
{
return [
'yii\base\Action' => YII2_PATH . '/base/Action.php',
'yii\base\ActionEvent' => YII2_PATH . '/base/ActionEvent.php',
'yii\base\ActionFilter' => YII2_PATH . '/base/ActionFilter.php',
'yii\base\Application' => YII2_PATH . '/base/Application.php',
'yii\base\ArrayAccessTrait' => YII2_PATH . '/base/ArrayAccessTrait.php',
'yii\base\Arrayable' => YII2_PATH . '/base/Arrayable.php',
];
} Yii::$container = new yii\di\Container();
} $config = array(
'id'=>'app-debugmodule',
'basePath'=>dirname(__DIR__),
'controllerNamespace'=>'debugmodule\controllers',
'defaultRoute'=>'index/index',
'params'=>[
'adminEmail' => 'admin@example.com',
'supportEmail' => 'support@example.com',
'user.passwordResetTokenExpire' => 3600,
],
'components'=>array_merge(
[
'cache' => [
'class' => 'yii\caching\FileCache',
'cachePath' => '@runtime/cache',
],
'log' => [
'class' => 'yii\log\Dispatcher',
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
'enabled' => true,
'logFile'=>'@runtime/logs/app.log',
'categories' => [], // 全部记录
'except' => ['yii\db\*'], // 不记录的分类
'logVars' => [],
// 'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'],
],
],
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'transport' => array( // 发送到互联网的传输方法
'class'=>'Swift_Transport_MailTransport',
'constructArgs'=>array(
array('class'=>'Swift_Transport_SimpleMailInvoker'),
array('class'=>'Swift_Events_SimpleEventDispatcher')
)
)
],
'security' => [
'class' => 'yii\base\Security'
],
'i18n' => [
'class' => 'yii\i18n\I18N',
'translations'=>[
'common'=>[ // 语言转换器
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '@common/messages',
],
'debugmodule'=>[
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '@debugmodule/messages',
],
'*'=>[ // 默认语言转换器
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '@common/messages',
]
]
],
// radis
'redis' => [
'class' => 'yii\redis\Connection',
'password'=>'123456',
'database'=>'database0',
],
// 队列
'queue' => [
'class' => \yii\queue\redis\Queue::class,
'redis' => 'redis',
'channel' => 'defaultqueue'
],
],
require (__DIR__ . '/components.php')
),
'modules'=>array_merge(
require (__DIR__ . '/../../common/config/modules.php'),
require (__DIR__ . '/modules.php')
),
'bootstrap' => ['log'],
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'language'=>'zh-CN', // 用户配置的语言
'timeZone'=>'PRC',
); /*
{
构造函数
{
预初始化配置
{
设置 basePath 路径
设置 vendorPath 路径
设置 runtimePath 路径
设置 timeZone 时区
配置 container
核心组件添加到 $config 中
} 注册错误处理器
{
异常处理器
错误处理器
崩溃处理器
} 配置 & 初始化
{
设置 $config 中的属性到 \yii\web\Application 初始化
{
注册别名
{
Yii::setAlias('@webroot', dirname($request->getScriptFile()));
Yii::setAlias('@web', $request->getBaseUrl());
}
调用组件的 bootstrap 方法
} }
} 执行
{
触发 self::EVENT_BEFORE_REQUEST 事件
解析路由
创建 Controller 对象
{
查找 \yii\web\Application->controllerMap 的配置
递归查找 模块 的配置
创建 Controller 对象
} 执行 Action
{
创建 Action 对象
{
查找 Controller 中的 actions 方法 是否存在 action 对象的映射,直接返回Action对象
反射查找action方法,创建\yii\base\InlineAction对象
} 执行 Action 对象
{
从父模块到子模块的,依次调用模块的 beforeAction 方法
触发 self::EVENT_BEFORE_ACTION 事件
识别 action 绑定的参数,调用 action 方法
触发 self::EVENT_AFTER_ACTION 事件
从子模块到父模块的,依次调用模块的 afterAction 方法
}
} 触发 self::EVENT_AFTER_REQUEST 事件
}
} */
(new yii\web\Application($config))
{
\yii\base\Application::__construct()
{
Yii::$app = $this;
static::setInstance($this);
{
if ($instance === null) {
unset(Yii::$app->loadedModules[get_called_class()]);
} else {
Yii::$app->loadedModules[get_class($instance)] = $instance;
}
} $this->state = self::STATE_BEGIN; $this->preInit($config);
{
if (!isset($config['id'])) {
throw new InvalidConfigException('The "id" configuration for the Application is required.');
}
if (isset($config['basePath'])) { // basePath 路径
$this->setBasePath($config['basePath']);
{
parent::setBasePath($path);
Yii::setAlias('@app', $this->getBasePath()); // 设置别名
}
unset($config['basePath']);
} else {
throw new InvalidConfigException('The "basePath" configuration for the Application is required.');
} if (isset($config['vendorPath'])) { // vendorPath 路径
$this->setVendorPath($config['vendorPath']);
{
// @@vendor、@vendor、
$this->_vendorPath = Yii::getAlias($path);
Yii::setAlias('@vendor', $this->_vendorPath); // 设置别名
Yii::setAlias('@bower', $this->_vendorPath . DIRECTORY_SEPARATOR . 'bower');
Yii::setAlias('@npm', $this->_vendorPath . DIRECTORY_SEPARATOR . 'npm');
}
unset($config['vendorPath']);
} else {
// set "@vendor"
$this->getVendorPath();
}
if (isset($config['runtimePath'])) { // runtimePath 路径
$this->setRuntimePath($config['runtimePath']);
{
$this->_runtimePath = Yii::getAlias($path);
Yii::setAlias('@runtime', $this->_runtimePath); // 设置别名
}
unset($config['runtimePath']);
} else {
// set "@runtime"
$this->getRuntimePath();
} if (isset($config['timeZone'])) { // timeZone 时区
$this->setTimeZone($config['timeZone']);
{
date_default_timezone_set($value);
}
unset($config['timeZone']);
} elseif (!ini_get('date.timezone')) {
$this->setTimeZone('UTC');
} if (isset($config['container'])) {
$this->setContainer($config['container']);
{
Yii::configure(Yii::$container, $config); // 配置 container
} unset($config['container']);
} // merge core components with custom components
foreach ($this->coreComponents(){
\yii\web\Application::coreComponents
{
return array_merge(parent::coreComponents(){
return [
'log' => ['class' => 'yii\log\Dispatcher'],
'view' => ['class' => 'yii\web\View'],
'formatter' => ['class' => 'yii\i18n\Formatter'],
'i18n' => ['class' => 'yii\i18n\I18N'],
'mailer' => ['class' => 'yii\swiftmailer\Mailer'],
'urlManager' => ['class' => 'yii\web\UrlManager'],
'assetManager' => ['class' => 'yii\web\AssetManager'],
'security' => ['class' => 'yii\base\Security'],
];
}, [
'request' => ['class' => 'yii\web\Request'],
'response' => ['class' => 'yii\web\Response'],
'session' => ['class' => 'yii\web\Session'],
'user' => ['class' => 'yii\web\User'],
'errorHandler' => ['class' => 'yii\web\ErrorHandler'],
]);
} } as $id => $component) { // 核心组件添加到 $config 中
if (!isset($config['components'][$id])) {
$config['components'][$id] = $component;
} elseif (is_array($config['components'][$id]) && !isset($config['components'][$id]['class'])) {
$config['components'][$id]['class'] = $component['class'];
}
}
} $this->registerErrorHandler($config); // 注册错误处理器
{
if (YII_ENABLE_ERROR_HANDLER) {
if (!isset($config['components']['errorHandler']['class'])) {
echo "Error: no errorHandler component is configured.\n";
exit(1);
}
$this->set('errorHandler', $config['components']['errorHandler']);
unset($config['components']['errorHandler']);
$this->getErrorHandler()->register();
{
\yii\base\ErrorHandler::register()
{
ini_set('display_errors', false);
set_exception_handler([$this, 'handleException']); // 异常处理器
if (defined('HHVM_VERSION')) {
set_error_handler([$this, 'handleHhvmError']);
} else {
set_error_handler([$this, 'handleError']); // 错误处理器
}
if ($this->memoryReserveSize > 0) {
$this->_memoryReserve = str_repeat('x', $this->memoryReserveSize);
}
register_shutdown_function([$this, 'handleFatalError']); // 崩溃处理器
} }
}
} Component::__construct($config);
{
if (!empty($config)) {
Yii::configure($this, $config); // 设置 $config 中的属性到 \yii\web\Application
{
foreach ($config as $name => $value) {
$object->$name = $value;
}
return $object;
}
} $this->init();
{
\yii\base\Application::init
{
$this->state = self::STATE_INIT;
$this->bootstrap();
{
\yii\web\Application::bootstrap()
{
$request = $this->getRequest();
Yii::setAlias('@webroot', dirname($request->getScriptFile()));
Yii::setAlias('@web', $request->getBaseUrl()); parent::bootstrap();
{
\yii\base\Application::bootstrap()
{
if ($this->extensions === null) {
$file = Yii::getAlias('@vendor/yiisoft/extensions.php');
$this->extensions = is_file($file) ? include($file) : [];
}
foreach ($this->extensions as $extension) {
if (!empty($extension['alias'])) {
foreach ($extension['alias'] as $name => $path) {
Yii::setAlias($name, $path);
}
}
if (isset($extension['bootstrap'])) {
$component = Yii::createObject($extension['bootstrap']);
if ($component instanceof BootstrapInterface) {
Yii::trace('Bootstrap with ' . get_class($component) . '::bootstrap()', __METHOD__);
$component->bootstrap($this);
} else {
Yii::trace('Bootstrap with ' . get_class($component), __METHOD__);
}
}
} foreach ($this->bootstrap as $class) { // 要立即启动的组件,$this->bootstrap = ['log']
$component = null;
if (is_string($class)) {
if ($this->has($class)) {
$component = $this->get($class); // 获取组件
} elseif ($this->hasModule($class)) {
$component = $this->getModule($class);
} elseif (strpos($class, '\\') === false) {
throw new InvalidConfigException("Unknown bootstrapping component ID: $class");
}
}
if (!isset($component)) {
$component = Yii::createObject($class);
} if ($component instanceof BootstrapInterface) {
Yii::trace('Bootstrap with ' . get_class($component) . '::bootstrap()', __METHOD__);
$component->bootstrap($this); // 调用组件的 bootstrap 方法
} else {
Yii::trace('Bootstrap with ' . get_class($component), __METHOD__);
}
}
}
}
}
}
}
}
}
}
}->run();{
\yii\base\Application::run()
{
try { $this->state = self::STATE_BEFORE_REQUEST;
$this->trigger(self::EVENT_BEFORE_REQUEST); // 触发事件
{
$this->ensureBehaviors();
{
if ($this->_behaviors === null) { 当 $this->_behaviors 为 null
$this->_behaviors = []; // 设置 $this->_behaviors 为空数组
foreach ($this->behaviors(){
return [];
} as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
{
if (!($behavior instanceof Behavior)) {
$behavior = Yii::createObject($behavior); // 创建 $behavior 对象
}
if (is_int($name)) { // 没有指定 $behavior 的 name
$behavior->attach($this); // 调用 $behavior 的 attach 方法
$this->_behaviors[] = $behavior;
} else {
if (isset($this->_behaviors[$name])) {
$this->_behaviors[$name]->detach(); // 调用 $behavior 的 detach 方法
}
$behavior->attach($this); // 调用 $behavior 的 attach 方法
{
如:$behavior = \yii\filters\RateLimiter
\yii\base\ActionFilter::attach($owner)
{
$this->owner = $owner; // $owner === \yii\web\Application
$owner->on(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']); // 注册事件
{
\yii\base\Component::on($name, $handler, $data = null, $append = true)
{
$this->ensureBehaviors();
if ($append || empty($this->_events[$name])) {
$this->_events[$name][] = [$handler, $data]; // 增加事件处理器
} else {
array_unshift($this->_events[$name], [$handler, $data]);
}
}
}
}
}
$this->_behaviors[$name] = $behavior;
} return $behavior;
}
}
}
}
if (!empty($this->_events[$name])) {
if ($event === null) {
$event = new Event; // 创建 $event 对象
}
if ($event->sender === null) {
$event->sender = $this;
}
$event->handled = false;
$event->name = $name;
foreach ($this->_events[$name] as $handler) { // 事件处理器列表
$event->data = $handler[1]; // 事件处理器的参数
call_user_func($handler[0], $event); // 调用事件处理器
// stop further handling if the event is handled
if ($event->handled) {
return;
}
}
}
// invoke class-level attached handlers
Event::trigger($this, $name, $event); // 调用类级别的事件处理器
{
\yii\base\Event::trigger($class, $name, $event = null)
{
if (empty(self::$_events[$name])) {
return;
}
if ($event === null) {
$event = new static;
}
$event->handled = false;
$event->name = $name; if (is_object($class)) { // 如 $class === \yii\web\Application
if ($event->sender === null) {
$event->sender = $class;
}
$class = get_class($class);
} else {
$class = ltrim($class, '\\');
} $classes = array_merge(
[$class],
class_parents($class, true),
class_implements($class, true)
); /*
self::$_events = [
\yii\web\Application::EVENT_BEFORE_REQUEST=>[
\yii\web\Application::class=>[
[$handlerFunc0,$data0]
[$handlerFunc1,$data1]
]
]
]
*/
foreach ($classes as $class) {
if (empty(self::$_events[$name][$class])) {
continue;
} foreach (self::$_events[$name][$class] as $handler) { // 事件处理器
$event->data = $handler[1];
call_user_func($handler[0], $event);
if ($event->handled) {
return;
}
}
}
} } } $this->state = self::STATE_HANDLING_REQUEST;
$response = $this->handleRequest($this->getRequest()); // 处理请求
{
\yii\web\Application::handleRequest($request)
{
if (empty($this->catchAll)) { // 没有配置全局捕获
try {
list ($route, $params) = $request->resolve(); // 解析路由
{
$result = Yii::$app->getUrlManager()->parseRequest($this);
{
\yii\web\UrlManager::parseRequest($request)
{
if ($this->enablePrettyUrl) { // 使用伪静态
/* @var $rule UrlRule */
foreach ($this->rules as $rule) {
$result = $rule->parseRequest($this, $request);
if (YII_DEBUG) {
Yii::trace([
'rule' => method_exists($rule, '__toString') ? $rule->__toString() : get_class($rule),
'match' => $result !== false,
'parent' => null,
], __METHOD__);
}
if ($result !== false) {
return $result;
}
} if ($this->enableStrictParsing) {
return false;
} Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__); $suffix = (string) $this->suffix;
$pathInfo = $request->getPathInfo();
$normalized = false;
if ($this->normalizer !== false) {
$pathInfo = $this->normalizer->normalizePathInfo($pathInfo, $suffix, $normalized);
}
if ($suffix !== '' && $pathInfo !== '') {
$n = strlen($this->suffix);
if (substr_compare($pathInfo, $this->suffix, -$n, $n) === 0) {
$pathInfo = substr($pathInfo, 0, -$n);
if ($pathInfo === '') {
// suffix alone is not allowed
return false;
}
} else {
// suffix doesn't match
return false;
}
} if ($normalized) {
// pathInfo was changed by normalizer - we need also normalize route
return $this->normalizer->normalizeRoute([$pathInfo, []]);
} else {
return [$pathInfo, []];
}
} else {
Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__);
$route = $request->getQueryParam($this->routeParam, ''); // $routeParam = 'r'; // 不使用伪静态
if (is_array($route)) {
$route = '';
} return [(string) $route, []];
}
}
} // 路由识别结束,获取Query参数
if ($result !== false) {
list ($route, $params) = $result;
if ($this->_queryParams === null) {
$_GET = $params + $_GET; // preserve numeric keys
} else {
$this->_queryParams = $params + $this->_queryParams;
}
return [$route, $this->getQueryParams()];
} throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'));
}
} catch (UrlNormalizerRedirectException $e) {
$url = $e->url;
if (is_array($url)) {
if (isset($url[0])) {
// ensure the route is absolute
$url[0] = '/' . ltrim($url[0], '/');
}
$url += $request->getQueryParams();
}
return $this->getResponse()->redirect(Url::to($url, $e->scheme), $e->statusCode);
}
} else {
$route = $this->catchAll[0];
$params = $this->catchAll;
unset($params[0]);
}
try { Yii::trace("Route requested: '$route'", __METHOD__);
$this->requestedRoute = $route; // 识别到的路由,如: $route = "/database-module/keyvalue-sample/redis-demo/foo-method"
$result = $this->runAction($route, $params); // 执行action
{
\yii\base\Module::runAction($route, $params = [])
{
$parts = $this->createController($route); // 创建 Controller 对象
{
if ($route === '') {
$route = $this->defaultRoute; // 'default'
} // double slashes or leading/ending slashes may cause substr problem
$route = trim($route, '/');
if (strpos($route, '//') !== false) {
return false;
} if (strpos($route, '/') !== false) {
list ($id, $route) = explode('/', $route, 2);
} else {
$id = $route;
$route = '';
} // module and controller map take precedence
if (isset($this->controllerMap[$id])) { // 查找 \yii\web\Application->controllerMap 的配置
$controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
return [$controller, $route];
}
$module = $this->getModule($id); // 查找 模块 的配置
{
\yii\base\Module::getModule($id, $load = true)
{
if (($pos = strpos($id, '/')) !== false) {
// sub-module
$module = $this->getModule(substr($id, 0, $pos)); // 递归查找"子模块" return $module === null ? null : $module->getModule(substr($id, $pos + 1), $load);
} if (isset($this->_modules[$id])) {
if ($this->_modules[$id] instanceof Module) {
return $this->_modules[$id];
} elseif ($load) {
Yii::trace("Loading module: $id", __METHOD__);
/* @var $module Module */
$module = Yii::createObject($this->_modules[$id], [$id, $this]); // 创建模块
{
\yii\base\Module::__construct($id, $parent = null, $config = [])
{
$this->id = $id; // 模块 Id,如:$id = 'database-module'
$this->module = $parent; // 父级别模块,如:$parent = \yii\web\Application
parent::__construct($config);
}
}
$module->setInstance($module); // 对自身的依赖
return $this->_modules[$id] = $module; // 设置模块到父级别的_modules中
}
} return null;
}
}
if ($module !== null) {
return $module->createController($route); // 递归调用 创建 Controller 对象
} if (($pos = strrpos($route, '/')) !== false) { // 最右边的"/"
$id .= '/' . substr($route, 0, $pos);
$route = substr($route, $pos + 1);
} $controller = $this->createControllerByID($id);
{
// 如: $id = 'redis-demo'
$pos = strrpos($id, '/'); // 控制器id中的"/"
if ($pos === false) {
$prefix = '';
$className = $id;
} else { // 控制器id中带有"/"
$prefix = substr($id, 0, $pos + 1); // 签字
$className = substr($id, $pos + 1);
} // 如: $className = 'redis-demo'
if (!preg_match('%^[a-z][a-z0-9\\-_]*$%', $className)) { // 只支持小写字母、数字、横杠、下划线
return null;
}
if ($prefix !== '' && !preg_match('%^[a-z0-9_/]+$%i', $prefix)) { // 只支持小写字母、数字
return null;
} $className = str_replace(' ', '', ucwords(str_replace('-', ' ', $className))) . 'Controller'; // 横杠转成驼峰
// 如: $className = 'RedisDemoController' $className = ltrim($this->controllerNamespace . '\\' . str_replace('/', '\\', $prefix) . $className, '\\'); // 拼接 Controller 的类名
if (strpos($className, '-') !== false || !class_exists($className)) {
return null;
} if (is_subclass_of($className, 'yii\base\Controller')) { // 是 yii\base\Controller 的子类
// 如: $id = 'redis-demo'
$controller = Yii::createObject($className, [$id, $this]); // 创建 Controller 对象
{
\yii\base\Controller::__construct($id, $module, $config = [])
{
$this->id = $id; // 如: $id = 'redis-demo'
$this->module = $module; // 如:$module = \yii\web\Application 或者 \debugmodule\modules\module0\Module
parent::__construct($config);
}
}
return get_class($controller) === $className ? $controller : null;
} elseif (YII_DEBUG) {
throw new InvalidConfigException("Controller class must extend from \\yii\\base\\Controller.");
}
return null;
}
if ($controller === null && $route !== '') {
$controller = $this->createControllerByID($id . '/' . $route); // controller下存在子目录
$route = '';
} return $controller === null ? false : [$controller, $route];
} if (is_array($parts)) {
/* @var $controller Controller */
// 如:$controller === 'RedisDemoController' 对象
// 如:$actionID === 'foo-method'
list($controller, $actionID) = $parts;
$oldController = Yii::$app->controller;
Yii::$app->controller = $controller;
$result = $controller->runAction($actionID, $params);
{
\yii\base\Controller::runAction($id, $params = [])
{
$action = $this->createAction($id);
{
// 如:$id === 'foo-method'
\yii\base\Controller::createAction($id)
{
if ($id === '') {
$id = $this->defaultAction; // $defaultAction = 'index';
} $actionMap = $this->actions(); // Controller 中的 actions 方法
{
return [];
} if (isset($actionMap[$id])) { // 存在 action 对象的映射
return Yii::createObject($actionMap[$id], [$id, $this]); // 创建 action 对象
} elseif (preg_match('/^[a-z0-9\\-_]+$/', $id) && strpos($id, '--') === false && trim($id, '-') === $id) {
$methodName = 'action' . str_replace(' ', '', ucwords(implode(' ', explode('-', $id)))); // 下划线转成驼峰
// 如:$methodName = 'actionFooMethod'
if (method_exists($this, $methodName)) {
$method = new \ReflectionMethod($this, $methodName);
if ($method->isPublic() && $method->getName() === $methodName) { // 公有的
return new InlineAction($id, $this, $methodName);
{
\yii\base\InlineAction::__construct($id, $controller, $actionMethod, $config = [])
{
$this->actionMethod = $actionMethod; // $actionMethod = 'actionFooMethod'
parent::__construct($id, $controller, $config);
{
\yii\base\Action::__construct($id, $controller, $config = [])
{
$this->id = $id; // 如:$id === 'foo-method'
$this->controller = $controller; // 如:$controller === Controller 对象
parent::__construct($config);
}
}
} }
}
}
} return null;
}
}
if ($action === null) {
throw new InvalidRouteException('Unable to resolve the request: ' . $this->getUniqueId() . '/' . $id);
} Yii::trace('Route to run: ' . $action->getUniqueId(), __METHOD__); if (Yii::$app->requestedAction === null) {
Yii::$app->requestedAction = $action;
} $oldAction = $this->action;
$this->action = $action; $modules = [];
$runAction = true; // call beforeAction on modules
foreach ($this->getModules(){ // 递归获取父级别的模块$module
$modules = [$this->module];
$module = $this->module; // 模块
while ($module->module !== null) { // 有父模块
array_unshift($modules, $module->module); // 父模块放到栈顶
$module = $module->module;
}
return $modules;
} as $module) {
if ($module->beforeAction($action)) { // 从父模块到子模块的,依次调用模块的 beforeAction 方法
array_unshift($modules, $module); // 父模块放到栈底
} else {
$runAction = false;
break;
}
} $result = null; if ($runAction && $this->beforeAction($action){
\yii\base\Controller::beforeAction($action)
{
$event = new ActionEvent($action);
$this->trigger(self::EVENT_BEFORE_ACTION, $event); // 触发事件
{
$this->ensureBehaviors();
{
if ($this->_behaviors === null) { 当 $this->_behaviors 为 null
$this->_behaviors = []; // 设置 $this->_behaviors 为空数组
foreach ($this->behaviors(){
return [];
} as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
{
if (!($behavior instanceof Behavior)) {
$behavior = Yii::createObject($behavior); // 创建 $behavior 对象
}
if (is_int($name)) { // 没有指定 $behavior 的 name
$behavior->attach($this); // 调用 $behavior 的 attach 方法
$this->_behaviors[] = $behavior;
} else {
if (isset($this->_behaviors[$name])) {
$this->_behaviors[$name]->detach(); // 调用 $behavior 的 detach 方法
}
$behavior->attach($this); // 调用 $behavior 的 attach 方法
{
如:$behavior = \yii\filters\RateLimiter
\yii\base\ActionFilter::attach($owner)
{
$this->owner = $owner; // $owner === \yii\web\Application
$owner->on(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']); // 注册事件
{
\yii\base\Component::on($name, $handler, $data = null, $append = true)
{
$this->ensureBehaviors();
if ($append || empty($this->_events[$name])) {
$this->_events[$name][] = [$handler, $data]; // 增加事件处理器
} else {
array_unshift($this->_events[$name], [$handler, $data]);
}
}
}
}
}
$this->_behaviors[$name] = $behavior;
} return $behavior;
}
}
}
}
if (!empty($this->_events[$name])) {
if ($event === null) {
$event = new Event; // 创建 $event 对象
}
if ($event->sender === null) {
$event->sender = $this;
}
$event->handled = false;
$event->name = $name;
foreach ($this->_events[$name] as $handler) { // 事件处理器列表
$event->data = $handler[1]; // 事件处理器的参数
call_user_func($handler[0], $event); // 调用事件处理器
// stop further handling if the event is handled
if ($event->handled) {
return;
}
}
}
// invoke class-level attached handlers
Event::trigger($this, $name, $event); // 调用类级别的事件处理器
{
\yii\base\Event::trigger($class, $name, $event = null)
{
if (empty(self::$_events[$name])) {
return;
}
if ($event === null) {
$event = new static;
}
$event->handled = false;
$event->name = $name; if (is_object($class)) { // 如 $class === \yii\web\Application
if ($event->sender === null) {
$event->sender = $class;
}
$class = get_class($class);
} else {
$class = ltrim($class, '\\');
} $classes = array_merge(
[$class],
class_parents($class, true),
class_implements($class, true)
); /*
self::$_events = [
\yii\base\Controller::EVENT_BEFORE_ACTION=>[
\yii\base\Controller::class=>[
[$handlerFunc0,$data0]
[$handlerFunc1,$data1]
]
]
]
*/
foreach ($classes as $class) {
if (empty(self::$_events[$name][$class])) {
continue;
} foreach (self::$_events[$name][$class] as $handler) { // 事件处理器
$event->data = $handler[1];
call_user_func($handler[0], $event);
if ($event->handled) {
return;
}
}
}
} }
}
return $event->isValid;
}
}) { // 触发事件,并且返回 true // run the action
$result = $action->runWithParams($params);
{
\yii\base\InlineAction::runWithParams($params)
{
$args = $this->controller->bindActionParams($this, $params);
{
\yii\web\Controller::bindActionParams($action, $params)
{
if ($action instanceof InlineAction) { // 反射 action 参数
$method = new \ReflectionMethod($this, $action->actionMethod);
} else {
$method = new \ReflectionMethod($action, 'run');
} $args = [];
$missing = [];
$actionParams = [];
foreach ($method->getParameters() as $param) { // action 方法的参数
$name = $param->getName(); // 参数名
if (array_key_exists($name, $params)) {
if ($param->isArray()) {
$args[] = $actionParams[$name] = (array) $params[$name];
} elseif (!is_array($params[$name])) {
$args[] = $actionParams[$name] = $params[$name];
} else {
throw new BadRequestHttpException(Yii::t('yii', 'Invalid data received for parameter "{param}".', [
'param' => $name,
]));
}
unset($params[$name]);
} elseif ($param->isDefaultValueAvailable()) { // 参数有默认值
$args[] = $actionParams[$name] = $param->getDefaultValue();
} else {
$missing[] = $name;
}
} if (!empty($missing)) {
throw new BadRequestHttpException(Yii::t('yii', 'Missing required parameters: {params}', [
'params' => implode(', ', $missing),
]));
} $this->actionParams = $actionParams; return $args;
}
} Yii::trace('Running action: ' . get_class($this->controller) . '::' . $this->actionMethod . '()', __METHOD__);
if (Yii::$app->requestedParams === null) {
Yii::$app->requestedParams = $args;
} return call_user_func_array([$this->controller, $this->actionMethod], $args); // 调用 action 方法 }
} $result = $this->afterAction($action, $result);
{
\yii\base\Controller::afterAction($action, $result)
{
$event = new ActionEvent($action);
$event->result = $result;
$this->trigger(self::EVENT_AFTER_ACTION, $event); // 触发事件
return $event->result;
}
} // call afterAction on modules
foreach ($modules as $module) { // 从子模块到父模块的,依次调用模块的 afterAction 方法
/* @var $module Module */
$result = $module->afterAction($action, $result);
}
} if ($oldAction !== null) {
$this->action = $oldAction;
} return $result;
}
}
if ($oldController !== null) {
Yii::$app->controller = $oldController;
} return $result;
} $id = $this->getUniqueId();
throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
} }
if ($result instanceof Response) { // 响应结果,action 返回的结果是对象
return $result;
} else {
$response = $this->getResponse();
if ($result !== null) {
$response->data = $result; // 响应结果,action 返回的结果是字符串
} return $response;
}
} catch (InvalidRouteException $e) {
throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'), $e->getCode(), $e);
}
}
} $this->state = self::STATE_AFTER_REQUEST;
$this->trigger(self::EVENT_AFTER_REQUEST); $this->state = self::STATE_SENDING_RESPONSE;
$response->send(); // 发送响应数据 $this->state = self::STATE_END; return $response->exitStatus; } catch (ExitException $e) { // 出现异常 $this->end($e->statusCode, isset($response) ? $response : null);
{
if ($this->state === self::STATE_BEFORE_REQUEST || $this->state === self::STATE_HANDLING_REQUEST) {
$this->state = self::STATE_AFTER_REQUEST;
$this->trigger(self::EVENT_AFTER_REQUEST);
} if ($this->state !== self::STATE_SENDING_RESPONSE && $this->state !== self::STATE_END) {
$this->state = self::STATE_END;
$response = $response ? : $this->getResponse();
$response->send(); // 发送响应数据
} if (YII_ENV_TEST) {
throw new ExitException($status);
} else {
exit($status);
}
}
return $e->statusCode; }
}
}

  

Yii 2.0.6 - 从入口到Action执行的更多相关文章

  1. YII 1.0 隐藏单入口index.php 设置路由与伪静态

    隐藏 index.php 保证apache配置文件httpd.conf里的LoadModulerewrite_module modules/mod_rewrite.so开启(去掉#)将相对应目录的Al ...

  2. [Yii2.0] 以Yii 2.0风格加载自定义类或命名空间 [配置使用Yii2 autoloader]

    Yii 2.0最显著的特征之一就是引入了命名空间,因此对于自定义类的引入方式也同之前有所不同.这篇文章讨论一下如何利用Yii 2.0的自动加载机制,向系统中引入自定义类和命名空间.本文旨在抛砖引玉,如 ...

  3. 使用nginx部署Yii 2.0\yii-basic-app-2.0.5

    nginx.conf #user nobody;worker_processes 1; #error_log logs/error.log;#error_log logs/error.log noti ...

  4. MVC4.0 利用IActionFilter实现单一Action返回多种结果

    延续MVC4.0 实现单一Action返回多种结果,我们实现了在一个Action中根据前台请求方式的不同和请求内容的不同返回了多个结果,但是这种返回多个结果的业务逻辑并不通用.如果现在年纪Action ...

  5. Yii Framework2.0开发教程(5)数据库mysql性能

    继续<Yii Framework2.0开发教程(3)数据库mysql入门> 首先给予一定的尊重yii2数据库支持引进 Yii 基于 PHP's PDO一个成熟的数据库访问层的建立.它提供了 ...

  6. Yii 2.0.3 Advanced版控制器不能包含大写字母的Bug

    Yii 2.0.3 Advanced版控制器不能包含大写字母的Bug,我是直接下载Archive文件安装的,非Composer方式安装 Yii 框架之前是支持在Url中包含大写字母的 最新的Yii 2 ...

  7. 08 Zabbix4.0系统配置事件通知 - 动作Action

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 08 Zabbix4.0系统配置事件通知 - 动作Action 请点击查看Zabbix3.0.8版 ...

  8. 阻止YII 1.0自动加载内置JQUERY库

    有些时候我们会在项目中用到很多js库, 因为Yii 1.0框架会默认自动加载一些自带核心库, 很容易引起冲突问题, 下面的代码就展示了如何在Yii 1.0框架下取消jQuery自动加载. Open C ...

  9. Yii 2.0 query模式语法

    项目使用Yii 2.0版本开发,个人一直喜好使用(new \yii\db\Query())模式操作数据,把增.删.查.改这4种情况的写法整理出来,方便查阅和记忆. 增加 - insert use Yi ...

随机推荐

  1. Java使用imageio、awt生成图片验证码

    1.生成验证码工具类 public class CheckCodeTool { private Integer width = 80; private Integer height = 38; pub ...

  2. 【Mood 21】要不要重复造轮子

    90%的人应该使用另外10%的人制造的轮子 但是每个人都应该有能力去创造属于自己的轮子 使用不代表伸手拿来,使用也是需要学习的,使用也可以升级为创新,关键在于这个轮子是在谁的手中! 90%的能套用着别 ...

  3. QTablewidget 简单例子

    [1]QTableWidget简介 QTableWidget是QT对话框设计中常用的显示数据表格的控件. 学习QTableWidget就要首先看看QTableView控件(控件也是有”家世“的!就像研 ...

  4. Filter学习总结,顺便提及点servlet3.0异步filter和异步监听

      Filter介绍:     Filter在项目中经常可以用到,通常配置在web.xml中.是服务器端的一个组件,对于用户的请求和响应数据进行过滤操作,控制是否让用户访问到对应的web资源.常用于编 ...

  5. BIEE入门(一)架构

    BIEE作为Oracle的新的商业智能平台企业版,起源于Oracle所收购的Siebel公司,BIEE原来叫做Siebel Analytic,但是Siebel也不是它的发明者,它是Siebel在200 ...

  6. Intel® Manager for Lustre* software(一)

    Intel® Manager for Lustre* software Installation 软件安装指导目录: 安装IML(Intel® Manager for Lustre* software ...

  7. May 12th 2017 Week 19th Friday

    Love asks faith, and faith asks firmness. 爱情要求忠诚,而忠诚要求坚贞. Love, as well as many other relations amon ...

  8. ABAP OPEN SQL里OPEN CURSOR和SELECT的比较

    OPEN CURSOR After the OPEN CURSOR statement, the database cursor is positioned in front of the first ...

  9. [USACO17FEB]Why Did the Cow Cross the Road II P

    嘟嘟嘟 考虑dp. 对于ai,和他能匹配的bj只有9个,所以我们考虑从这9个状态转移. 对于ai 能匹配的一个bj,当前最大的匹配数一定是[1, j - 1]中的最大匹配数 + 1.然后用树状数组维护 ...

  10. mysql中set和enum使用(简单介绍)

    简单介绍 SET类型 在创建表时,就指定SET类型的取值范围. 属性名 SET('值1','值2','值3'...,'值n') 其中,“属性名”参数指字段的名称:“值n”参数表示列表中的第n个值,这些 ...