PHPPhalcon 请求的生命周期
Posted 半塘少年
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHPPhalcon 请求的生命周期相关的知识,希望对你有一定的参考价值。
真实世界中当我们了解了一件工具的运行原理后,我们将能够更好的使用它,程序也是一样。现在框架大多是基于 MVC 的架构,Phalcon 也不例外。下面来看下 Phalcon 是如何来处理一个请求的。
首先看下 Phalcon 的入口程序 index.php
,一个最基础的入口文件,主要做了哪些事情。
<?php
use Phalcon\\Loader;
use Phalcon\\Mvc\\View;
use Phalcon\\Mvc\\Application;
use Phalcon\\Di\\FactoryDefault;
use Phalcon\\Mvc\\Url as UrlProvider;
use Phalcon\\Db\\Adapter\\Pdo\\mysql as DbAdapter;
// Register an autoloader
$loader = new Loader();
$loader->registerDirs( [
"../app/controllers/",
"../app/models/",
]);
$loader->register();
// Create a DI
$di = new FactoryDefault();
// Setup the view component
$di->set( "view", function () {
$view = new View();
$view->setViewsDir("../app/views/");
return $view;
});
// Setup a base URI so that all generated URIs include the "tutorial" folder
$di->set( "url", function () {
$url = new UrlProvider();
$url->setBaseUri("/tutorial/");
return $url;
});
$application = new Application($di);
try {
// Handle the request
$response = $application->handle();
$response->send();
} catch (\\Exception $e) {
echo "Exception: ", $e->getMessage();
}
程序中可以看到,入口文件主要干了以下事情:
- 创建自动加载器
$loader
,注册自动加载目录; - 创建服务容器
$di
, 注册服务(其他一些服务使用默认的,如:路由 Router 服务。可以打印$di
查看已注册的服务); - 创建程序对象
$application
,运行程序$application->handle()
; - 发送响应的内容。
从以上几点可以看出,程序的主要处理逻辑还是在 Application
的 handle()
函数中,在到 handle()
函数中看下它做了什么事。
// ################################################
// 源码文件 cphalcon/phalcon/mvc/application.zep
// 这里截取 handle() 函数出来看下,
// ################################################
/**
* Handles a MVC request
*/
public function handle(string uri = null) -> <ResponseInterface> | boolean
{
var dependencyInjector, eventsManager, router, dispatcher, response, view,
module, moduleObject, moduleName, className, path,
implicitView, returnedResponse, controller, possibleResponse,
renderStatus, matchedRoute, match;
let dependencyInjector = this->_dependencyInjector;
if typeof dependencyInjector != "object" {
throw new Exception("A dependency injection object is required to access internal services");
}
let eventsManager = <ManagerInterface> this->_eventsManager;
/**
* Call boot event, this allow the developer to perform initialization actions
*/
if typeof eventsManager == "object" {
if eventsManager->fire("application:boot", this) === false {
return false;
}
}
let router = <RouterInterface> dependencyInjector->getShared("router");
/**
* Handle the URI pattern (if any)
*/
router->handle(uri);
/**
* If a 'match' callback was defined in the matched route
* The whole dispatcher+view behavior can be overriden by the developer
*/
let matchedRoute = router->getMatchedRoute();
if typeof matchedRoute == "object" {
let match = matchedRoute->getMatch();
if match !== null {
if match instanceof \\Closure {
let match = \\Closure::bind(match, dependencyInjector);
}
/**
* Directly call the match callback
*/
let possibleResponse = call_user_func_array(match, router->getParams());
/**
* If the returned value is a string return it as body
*/
if typeof possibleResponse == "string" {
let response = <ResponseInterface> dependencyInjector->getShared("response");
response->setContent(possibleResponse);
return response;
}
/**
* If the returned string is a ResponseInterface use it as response
*/
if typeof possibleResponse == "object" {
if possibleResponse instanceof ResponseInterface {
possibleResponse->sendHeaders();
possibleResponse->sendCookies();
return possibleResponse;
}
}
}
}
/**
* If the router doesn't return a valid module we use the default module
*/
let moduleName = router->getModuleName();
if !moduleName {
let moduleName = this->_defaultModule;
}
let moduleObject = null;
/**
* Process the module definition
*/
if moduleName {
if typeof eventsManager == "object" {
if eventsManager->fire("application:beforeStartModule", this, moduleName) === false {
return false;
}
}
/**
* Gets the module definition
*/
let module = this->getModule(moduleName);
/**
* A module definition must ne an array or an object
*/
if typeof module != "array" && typeof module != "object" {
throw new Exception("Invalid module definition");
}
/**
* An array module definition contains a path to a module definition class
*/
if typeof module == "array" {
/**
* Class name used to load the module definition
*/
if !fetch className, module["className"] {
let className = "Module";
}
/**
* If developer specify a path try to include the file
*/
if fetch path, module["path"] {
if !class_exists(className, false) {
if !file_exists(path) {
throw new Exception("Module definition path '" . path . "' doesn't exist");
}
require path;
}
}
let moduleObject = <ModuleDefinitionInterface> dependencyInjector->get(className);
/**
* 'registerAutoloaders' and 'registerServices' are automatically called
*/
moduleObject->registerAutoloaders(dependencyInjector);
moduleObject->registerServices(dependencyInjector);
} else {
/**
* A module definition object, can be a Closure instance
*/
if !(module instanceof \\Closure) {
throw new Exception("Invalid module definition");
}
let moduleObject = call_user_func_array(module, [dependencyInjector]);
}
/**
* Calling afterStartModule event
*/
if typeof eventsManager == "object" {
eventsManager->fire("application:afterStartModule", this, moduleObject);
}
}
/**
* Check whether use implicit views or not
*/
let implicitView = this->_implicitView;
if implicitView === true {
let view = <ViewInterface> dependencyInjector->getShared("view");
}
/**
* We get the parameters from the router and assign them to the dispatcher
* Assign the values passed from the router
*/
let dispatcher = <DispatcherInterface> dependencyInjector->getShared("dispatcher");
dispatcher->setModuleName(router->getModuleName());
dispatcher->setNamespaceName(router->getNamespaceName());
dispatcher->setControllerName(router->getControllerName());
dispatcher->setActionName(router->getActionName());
dispatcher->setParams(router->getParams());
/**
* Start the view component (start output buffering)
*/
if implicitView === true {
view->start();
}
/**
* Calling beforeHandleRequest
*/
if typeof eventsManager == "object" {
if eventsManager->fire("application:beforeHandleRequest", this, dispatcher) === false {
return false;
}
}
/**
* The dispatcher must return an object
*/
let controller = dispatcher->dispatch();
/**
* Get the latest value returned by an action
*/
let possibleResponse = dispatcher->getReturnedValue();
/**
* Returning false from an action cancels the view
*/
if typeof possibleResponse == "boolean" && possibleResponse === false {
let response = <ResponseInterface> dependencyInjector->getShared("response");
} else {
/**
* Returning a string makes use it as the body of the response
*/
if typeof possibleResponse == "string" {
let response = <ResponseInterface> dependencyInjector->getShared("response");
response->setContent(possibleResponse);
} else {
/**
* Check if the returned object is already a response
*/
let returnedResponse = ((typeof possibleResponse == "object") && (possibleResponse instanceof ResponseInterface));
/**
* Calling afterHandleRequest
*/
if typeof eventsManager == "object" {
eventsManager->fire("application:afterHandleRequest", this, controller);
}
/**
* If the dispatcher returns an object we try to render the view in auto-rendering mode
*/
if returnedResponse === false && implicitView === true {
if typeof controller == "object" {
let renderStatus = true;
/**
* This allows to make a custom view render
*/
if typeof eventsManager == "object" {
let renderStatus = eventsManager->fire("application:viewRender", this, view);
}
/**
* Check if the view process has been treated by the developer
*/
if renderStatus !== false {
/**
* Automatic render based on the latest controller executed
*/
view->render(
dispatcher->getControllerName(),
dispatcher->getActionName(),
dispatcher->getParams()
);
}
}
}
/**
* Finish the view component (stop output buffering)
*/
if implicitView === true {
view->finish();
}
if returnedResponse === true {
/**
* We don't need to create a response because there is one already created
*/
let response = possibleResponse;
} else {
let response = <ResponseInterface> dependencyInjector->getShared("response");
if implicitView === true {
/**
* The content returned by the view is passed to the response service
*/
response->setContent(view->getContent());
}
}
}
}
/**
* Calling beforeSendResponse
*/
if typeof eventsManager == "object" {
eventsManager->fire("application:beforeSendResponse", this, response);
}
/**
* Headers and Cookies are automatically sent
*/
response->sendHeaders();
response->sendCookies();
/**
* Return the response
*/
return response;
}
函数handle()
里主要干了这些事:
- 匹配路由;
- 调用派遣器,分发匹配的路由;
- 渲染视图;
- 返回响应对象
response
。
还有一些事件处理,具体查看源码了解。所以可以看出 Phalcon 请求的生命周期大致如下图所示:
以上是关于PHPPhalcon 请求的生命周期的主要内容,如果未能解决你的问题,请参考以下文章
[译] ASP.NET 生命周期 – ASP.NET 请求生命周期