最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

第二部分 第1章 項目訪問解析

2023-09-06 17:33 作者:納西妲愛編程  | 我要投稿

第1章 項目訪問解析

1.1 PHP 項目訪問解析

PHP 交互的前提條件 ?

PHP 是一門動態(tài)的腳本編程語言,PHP可以通過 SAPI 來實現(xiàn)不同 PHP 腳本的執(zhí)行方式,以滿足在不同環(huán)境下的 PHP 代碼執(zhí)行,其中 Web 執(zhí)行模式就屬 FastCGI 的工作模式。FastCGI 由 FPM 實現(xiàn),那 FPM 是什么呢 ?

FPM 是 PHP 的進(jìn)程管理器,即 PHP 軟件程序啟動后,就會在后臺運(yùn)行 PHP 相關(guān)的進(jìn)程。那如果進(jìn)程意外掛掉、接受指令要完成什么工作。這時要怎么辦呢? 所以就需要 FPM 來統(tǒng)一的進(jìn)行進(jìn)程管理。

在 linux 下,通過 ps -ef | grep php 可查看所有啟動的 PHP 進(jìn)程,但你好像發(fā)現(xiàn)了,php-fpm 有很多啊。這個是咋回事呢?

這就不得不說下 PHP 的進(jìn)程架構(gòu),它并不是一個人,因為你一個人做事太慢,所以 PHP 就做了個分工,進(jìn)程由 Master+Worker 模式構(gòu)成,也就是進(jìn)程有多個,但不同進(jìn)程負(fù)責(zé)的工作是不一樣,也就是 2 種。

PHP 在啟動程序后就會先啟動 Master ,然后 fork 出多個 Worker 進(jìn)程,最后由 Worker 直接與客戶端建立請求連接。也就是 Master 做進(jìn)程管理的工作,一個 worker 做請求的連接與數(shù)據(jù)的處理。

有了進(jìn)程咱們是不是就可以執(zhí)行工作啦 ?

并不是,因為你進(jìn)程要執(zhí)行工作,是不需要讓別人把原材料(數(shù)據(jù))給你,也就數(shù)據(jù)。 但這個數(shù)據(jù)不可能無緣無故過來,一般都是通過 Nginx 傳輸過來的。但 Nginx 和 PHP 是 2 個程序呀,彼此都互不認(rèn)識。就像你和快遞小哥一樣,他要把包裹交到你手上,但你們彼此根本都不認(rèn)識。但你們會通過

手機(jī)號碼+包裹簽收

來進(jìn)行識別呢 !

所以 FPM 也一樣,它也需要實現(xiàn)一種規(guī)則,用來接受原材料,也就是進(jìn)行數(shù)據(jù)交互。這也就是為啥每個 PHP 進(jìn)程都支持 fast-cgi 協(xié)議的原因。有了它,咱們就可以讓 Nginx 和 PHP 打交道啦。

上面談到了,PHP 的工作模式與處理,那么在 PHP 的項目中,完整 PHP 請求的處理模式是怎么實現(xiàn)的 ?

用戶訪問域名,域名進(jìn)行 DNS 解析 -> 請求到對應(yīng) IP 服務(wù)器和端口。

根據(jù) IP 地址與端口發(fā)送請求到 IP 地址服務(wù)器上的 Nginx 軟件監(jiān)聽的對應(yīng)端口中。

Nginx 對請求 url 進(jìn)行 location 匹配,執(zhí)行匹配 location 下的規(guī)則,然后由 Nginx 轉(zhuǎn)發(fā)請求給 php 。

php-fpm 的 master 進(jìn)程監(jiān)聽到 nginx 請求,然后 Master 進(jìn)程將請求分配給其中一個閑置的 worker進(jìn)程。

最后由 worker 進(jìn)程執(zhí)行請求,并返回執(zhí)行結(jié)果給 nginx 。

Nginx 返回結(jié)果給用戶。

注意:這里的 Nginx 就是 web 服務(wù)器,類似的還有 Apache、IIS 等。

你可能會覺得,這個是PHP訪問的方式,那項目如何訪問呢 ?

你的項目基于 PHP 開發(fā),一般 PHP 部署在線上的環(huán)境都為 LNMP 架構(gòu),就是基于 Linux操作系統(tǒng)來搭建的 PHP 開發(fā)環(huán)境,那這時候,你 HTTP 請求訪問到服務(wù)器后,就自然把請求交給 Nginx,在由 Nginx 把請求交給項目的執(zhí)行文件,最后在進(jìn)行執(zhí)行處理的。

1.2 框架基準(zhǔn)請求響應(yīng)解析

MVC

談框架的基準(zhǔn)請求都不能離開 MVC 模式處理,一切請求都會先進(jìn)入到框架的 index.php 的入口文件中,然后在引入相關(guān)文件類庫,做框架初始化、請求驗證、路由分析,最后實例化控制器并調(diào)用方法去查找數(shù)據(jù)庫的數(shù)據(jù),最后在響應(yīng)給客戶端。

如上圖,為 MVC 原理圖,分別代表什么意思 ?

Model(模型)

- 模型代表一個存取數(shù)據(jù)的對象。它也可以帶有邏輯,在數(shù)據(jù)變化時更新控制器。

View(視圖)

- 視圖代表模型包含的數(shù)據(jù)的可視化

Controller(控制器)

- 控制器作用于模型和視圖上。它控制數(shù)據(jù)流向模型對象,并在數(shù)據(jù)變化時更新視圖。它使視圖與模型分離開 。

優(yōu)點 :

視圖控制模型分離, 提高代碼重用性。

提高開發(fā)效率。

便于后期維護(hù), 降低維護(hù)成本。

方便多開發(fā)人員間的分工。

缺點 :

方法越來越大,運(yùn)行效率相對較低 。

控制層和表現(xiàn)層有時會過于緊密,導(dǎo)致沒有真正分離和重用 。類本身也是越來越大,職責(zé)也會越來越多。

框架的請求執(zhí)行處理。

有了框架通用的 MVC 模式,接下來就可以看下框架的請求響應(yīng)流程。這里就以 laravel 請求周期來進(jìn)行舉例,其它一些框架與 Laravel 框架是類型的。如圖所示 :

注意:以下涉及代碼都為laravel框架核心代碼解析。

1 . 用戶的 HTTP 請求發(fā)送到 index.php 入口處。

2 . index.php 開始引入 app 應(yīng)用對象、異常處理機(jī)制、HTTP 等相關(guān)核心類庫,并進(jìn)行進(jìn)行相關(guān)初始化。

//laraveldemo\public\index.php

$app = require_once __DIR__.'/../bootstrap/app.php';

-----------------------------------------------------

//laraveldemo\bootstrap\app.php

$app = new Illuminate\Foundation\Application(

??$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)

);

$app->singleton(

??Illuminate\Contracts\Http\Kernel::class,

??App\Http\Kernel::class

);

$app->singleton(

??Illuminate\Contracts\Console\Kernel::class,

??App\Console\Kernel::class

);

$app->singleton(

?Illuminate\Contracts\Debug\ExceptionHandler::class,

??App\Exceptions\Handler::class

);

3 . 在 app 應(yīng)用內(nèi)部,注冊容器對象和文件類、路由、事件、日志、相關(guān)別名與類的關(guān)系等等到容器中。從而來完成框架的基礎(chǔ)初始化。這樣框架需要的基本服務(wù)功能就都有了。

文件位置:laraveldemo\vendor\laravel\framework\src\Illuminate\Foundation\Application.php

?public function __construct($basePath = null)

?{

if ($basePath) {

??$this->setBasePath($basePath);

}

?

$this->registerBaseBindings();

$this->registerBaseServiceProviders();

$this->registerCoreContainerAliases();

?}

?

??//$this->registerBaseBindings(); 將容器別名、文件類等基礎(chǔ)信息注入到容器

??protected function registerBaseBindings()

?{

static::setInstance($this);

?

$this->instance('app', $this);

?

$this->instance(Container::class, $this);

$this->singleton(Mix::class);

?

$this->singleton(PackageManifest::class, function () {

??return new PackageManifest(

new Filesystem, $this->basePath(), $this->getCachedPackagesPath()

?);

});

?}

-----------------------------------------------------

??// $this->registerBaseServiceProviders(); 注冊相關(guān)基礎(chǔ)服務(wù)

?protected function registerBaseServiceProviders()

?{

$this->register(new EventServiceProvider($this));

$this->register(new LogServiceProvider($this));

$this->register(new RoutingServiceProvider($this));

?}

-----------------------------------------------------

//$this->registerCoreContainerAliases();注冊別名和類的關(guān)系

public function registerCoreContainerAliases()

?{

foreach ([

??'app'?=> [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],

??'auth' => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],

??'auth.driver'?=>

//.......省略些核心代碼

??'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],

] as $key => $aliases) {

??foreach ($aliases as $alias) {

$this->alias($key, $alias);

?}

}

?}

???

}

4 . 完成了框架組件服務(wù)組裝,咱們就需要開始來解析 HTTP 請求啦?,F(xiàn)在可基于容器獲取到 HTTP 對象,在這里會通過 make 方法直接反射拿取 HTTP 實例。并調(diào)用 HTTP 類下面的 capture 方法獲取 HTTP 請求中的參數(shù),并用服務(wù)提供者把相關(guān)的服務(wù)類綁定到容器中,然后對請求通過中間件進(jìn)行過濾,通過后在進(jìn)行路由的匹配與代碼執(zhí)行操作。執(zhí)行完最后返回給客戶端。

//laraveldemo\public\index.php

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(?

??$request = Illuminate\Http\Request::capture());

//文件位置:laraveldemo\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php

-----------------------------------------------------

//應(yīng)用服務(wù)提供者,用來注冊其它相關(guān)的服務(wù)組件??

protected $bootstrappers = [????

\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,????

\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,????

\Illuminate\Foundation\Bootstrap\HandleExceptions::class,????

\Illuminate\Foundation\Bootstrap\RegisterFacades::class,????

\Illuminate\Foundation\Bootstrap\RegisterProviders::class,????

\Illuminate\Foundation\Bootstrap\BootProviders::class,?

];

//框架自帶中間件,用于請求上的參數(shù)過濾??

protected $middleware = [????

\App\Http\Middleware\TrustHosts::class,????

\App\Http\Middleware\TrustProxies::class,????

\Fruitcake\Cors\HandleCors::class,????

\App\Http\Middleware\CheckForMaintenanceMode::class,??

\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,????

\App\Http\Middleware\TrimStrings::class,????

\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,?

];??

?

public function handle($request)

{?

try {??????

$request->enableHttpMethodParameterOverride();??

//1、開始分發(fā)請求的路由??????

$response = $this->sendRequestThroughRouter($request);?

? } catch (Throwable $e) {??????

$this->reportException($e);??????

$response = $this->renderException($request, $e);???

}????

$this->app['events']->dispatch(??????

?? new RequestHandled($request, $response));????

?? return $response;??

}

//2、開啟路由分發(fā)之前,先獲取請求對象,然后開始注冊服務(wù)提供者。并在管道模式下面進(jìn)行中間件對HTTP請求的過濾檢查

protected function sendRequestThroughRouter($request)

{???

$this->app->instance('request', $request);????

Facade::clearResolvedInstance('request');

??//注冊服務(wù)提供者????

?? $this->bootstrap();

??//把相關(guān)需要做檢查的中間件放入管道對象中,基于遞歸函數(shù)進(jìn)行類的處理????

return (new Pipeline($this->app))->send($request)??????????

->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)??????????

->then($this->dispatchToRouter());??

}??

public function bootstrap()

{???

if (! $this->app->hasBeenBootstrapped()) {???

$this->app->bootstrapWith($this->bootstrappers());?

}??

}

protected function bootstrappers()?

{????

return $this->bootstrappers;??

}

5 . 請求首先通過中間件進(jìn)行請求的過濾,如果不滿足相關(guān)中間件的條件,就直接結(jié)束請求。

6 . 如果中間件處理成功,就會獲取請求中的 URL 地址與注冊的路由地址進(jìn)行比較,如果匹配到,就根據(jù)路由拿到控制器和方法名,然后進(jìn)行控制器實例化并調(diào)用注冊方法,在處理當(dāng)前的 HTTP 請求

?public function gatherRouteMiddleware(Route $route)

?{

$excluded = collect($route->excludedMiddleware())->map(function ($name) {

return (array) MiddlewareNameResolver::resolve(

$name, $this->middleware, $this->middlewareGroups);

})->flatten()->values()->all();

$middleware = collect($route->gatherMiddleware())->map(function ($name) {

return (array) MiddlewareNameResolver::resolve(

?? $name, $this->middleware, $this->middlewareGroups

);

? })->flatten()->reject(function ($name) use ($excluded) {

?? return in_array($name, $excluded, true);

})->values();

?

return $this->sortMiddleware($middleware);

}

////獲取 路由中 和 控制器中 定義的中間件單詞標(biāo)識

public function gatherMiddleware()

?{

if (! is_null($this->computedMiddleware)) {

?? return $this->computedMiddleware;

}

?

$this->computedMiddleware = [];

?

return $this->computedMiddleware = Router::uniqueMiddleware(array_merge(

?? $this->middleware(), $this->controllerMiddleware()

));

?}

?

public function controllerMiddleware()

{

if (! $this->isControllerAction()) {

?? return [];

}

// 調(diào)用 `controllerDispatcher` 獲取 控制器調(diào)度器 對象

// 調(diào)用 控制器調(diào)度器 對象中的 getMiddleware 方法,以 控制器對象 和 方法名 為參數(shù)

return $this->controllerDispatcher()->getMiddleware(

// 調(diào)用 getController 方法,獲取 控制器對象

?? $this->getController(), $this->getControllerMethod()

);

?}

?

protected function dispatchToRouter()

{

return function ($request) {

?? $this->app->instance('request', $request);

?? return $this->router->dispatch($request);

};

?}

?public function dispatch(Request $request)

?{

$this->currentRequest = $request;

return $this->dispatchToRoute($request);

?}

//查找路由并開始運(yùn)行路由對應(yīng)的控制器下的方法

public function dispatchToRoute(Request $request)

?{

? return $this->runRoute($request, $this->findRoute($request));

?}

7 . 請求處理完成后,通過 Responce 直接響應(yīng)業(yè)務(wù)數(shù)據(jù)到客戶端。

第二部分 第1章 項目訪問解析的評論 (共 條)

分享到微博請遵守國家法律
渝北区| 彭阳县| 甘泉县| 苏尼特左旗| 商水县| 浦县| 延川县| 出国| 阿鲁科尔沁旗| 徐水县| 原阳县| 府谷县| 鲁山县| 常熟市| 龙胜| 彭泽县| 南开区| 襄城县| 宁波市| 绥中县| 芷江| 屏南县| 法库县| 镇巴县| 镇赉县| 绥德县| 玛纳斯县| 芮城县| 涪陵区| 西盟| 仙桃市| 明水县| 达拉特旗| 宜阳县| 璧山县| 永州市| 丹棱县| 东城区| 吕梁市| 十堰市| 儋州市|