Magento 2 的入口是 index.php,有两个:
<your Magento install dir>/index.php
<your Magento install dir>/pub/index.php
简化后的入口像这样:
require __DIR__ . '/app/bootstrap.php';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
$app = $bootstrap->createApplication('Magento\Framework\App\Http');
$bootstrap->run($app);
第一句,就是将<your Magento install dir>/app/bootstrap.php
包含进来。这个bootstrap.php
文件主要做了一件事情,就是将<your Magento install dir>/app/autoload.php
和<your Magento install dir>/app/functions.php
包含进来。autoload.php
负责了Magneto 系统中所有类的自动加载。functions.php
负责翻译用的。
第二句,调用静态方法,返回实例给$bootstrap
第三句,调用$bootstrap
的createApplication
方法,该方法调用 Object Manager 创建了Magento\Framework\App\Http
实例。
第四句,将上一步骤的实例传递给$bootstrap->run()
下面进入\Magento\Framework\App\Bootstrap -> run
看一看,简化后的方法如下:
public function run(\Magento\Framework\AppInterface $application)
{
//PART-2-1
$this->initErrorHandler();
$this->initObjectManager();
$this->assertMaintenance();
$this->assertInstalled();
//PART-2-2
$response = $application->launch();
//PART-2-3
$response->sendResponse();
}
PART-2-1 handles the sort of housekeeping bits. It initializes the
custom error handler, initializes the object manager, checks if our application is in maintenance mode, and checks that it is installed.
PART-2-2 部分调用Magento\Framework\App\Http -> launch()
暂时把$response
看作是\Magento\Framework\App\Response\Http
类
PART-2-3 调用\Magento\Framework\App\Response\Http
实例的sendResponse
方法,该方法在该类的父类\Magento\Framework\HTTP\PhpEnvironment\Response
中。这个父类继承自\Zend\Http\PhpEnvironment\Response
不继续深入了。总之,到这个类为止,真正开始输出数据了。
总结一下,到目前为止的流程是:
- index.php
- \Magento\Framework\App\Bootstrap -> run
- \Magento\Framework\App\Http -> launch
- \Magento\Framework\App\Response\Http -> sendResponse
来看\Magento\Framework\App\Http -> launch
简化后是这样的:
public function launch()
{
// PART-3-1
$frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface');
// PART-3-2
$result = $frontController->dispatch($this->_request);
if ($result instanceof \Magento\Framework\Controller\ResultInterface) {
// PART-3-3
$result->renderResult($this->_response);
} elseif ($result instanceof \Magento\Framework\App\Response\HttpInterface {
$this->_response = $result;
} else {
throw new \InvalidArgumentException('Invalid return type');
}
// PART-3-4
return $this->_response;
}
PART-3-1 创建一个实现\Magento\Framework\App\FrontControllerInterface
接口的类的实例,具体是哪个接口,需要查看di.xml 文件。这个类一般是Magento\Framework\App\FrontController
。
PART-3-2 Magento\Framework\App\FrontController -> dispatch
具体的稍后再看。他的返回值一般$result
是\Magento\Framework\Controller\ResultInterface
,一般是\Magento\Framework\View\Result\Page
类
PART-3-3 执行$result->renderResult($this->_response)
这一步没有输出,只是对$this->_response
的修改,之后 PART-3-4 把$this->response
返回出去。
再总结一下,流程现在是:
- index.php
- \Magento\Framework\App\Bootstrap -> run
- \Magento\Framework\App\Http -> launch
- \Magento\Framework\App\FrontController -> dispatch
- \Magento\Framework\View\Result\Page -> renderResult
- \Magento\Framework\App\Response\Http -> sendResponse
\Magento\Framework\App\FrontController -> dispatch
需要更深入一下。简化后的方法是这样的:
public function dispatch(\Magento\Framework\App\RequestInterface $request)
{
// PART-4-1
while (!$request->isDispatched() && $routingCycleCounter++ < 100) {
//PART-4-2
foreach ($this->_routerList as $router) {
try {
//PART-4-3
$actionInstance = $router->match($request);
if ($actionInstance) {
$request->setDispatched(true);
//PART-4-4
$result = $actionInstance->dispatch($request);
break;
}
} catch (\Magento\Framework\Exception \NotFoundException $e) {}
}
}
// PART-4-5
return $result;
}
PART-4-1 和 PART-4-2 给每个$router
100次机会找出匹配项,避免死循环。
routers 有以下类型:
- Magento\Framework\App\Router\Base
- Magento\UrlRewrite\Controller\Router
- Magento\Cms\Controller\Router
- Magento\Framework\App\Router\DefaultRouter
他们都实现了\Magento\Framework\App\RouterInterface
以确保他们都实现了match
方法。match
返回的$actionInstance
是一个实现了\Magento\Framework\App\ActionInterface
接口的类的实例。
PART-4-4 $actionInstance
(比如 controller)继承自\Magento\Framework\App\Action\Action
类,返回\Magento\Framework\App\ResponseInterface
。在dispatch
方法中会执行controller
的execute
方法。
流程现在变成:
- index.php
- \Magento\Framework\App\Bootstrap -> run
- \Magento\Framework\App\Http -> launch
- \Magento\Framework\App\FrontController -> dispatch
- \Magento\Framework\App\Router\Base -> match
- \Magento\Framework\App\Action\Action -> dispatch
- \Magento\Framework\View\Result\Page -> renderResult
- \Magento\Framework\App\Response\Http -> sendResponse
总结,对前端开发者来说,controller 返回 Page 类型的对象后,会自动调用该page的 renderResult 方法。
Page and Layout is where all the theme translations, layout, and template loading are triggering
参考文档
Magento 2 Developer’s Guide by Branko Ajzele
Routing in Magento 2
Request Flow in Magento 2