精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

教你在不使用框架的情況下也能寫出現(xiàn)代化PHP代碼

開發(fā) 后端
我為你們準備了一個富有挑戰(zhàn)性的事情。接下來你們將以 無 框架的方式開啟一個項目之旅。也許無框架開發(fā)令你受益匪淺的地方就是,可以從底層運作的層面中汲取豐富的知識。拋卻依賴神奇的,幫你處理無法調試和無法真正理解的東西的框架,你將清楚的看到這一切是如何發(fā)生的。

[[225343]]

我為你們準備了一個富有挑戰(zhàn)性的事情。接下來你們將以 框架的方式開啟一個項目之旅。

首先聲明, 這篇并非又臭又長的反框架裹腳布文章。也不是推銷 非原創(chuàng) 思想 。畢竟, 我們還將在接下來的開發(fā)之旅中使用其他框架開發(fā)者編寫的輔助包。我對這個領域的創(chuàng)新也是持無可非議的態(tài)度。

這無關他人,而是關乎己身。作為一名開發(fā)者,它將有機會讓你成長。

也許無框架開發(fā)令你受益匪淺的地方就是,可以從底層運作的層面中汲取豐富的知識。拋卻依賴神奇的,幫你處理無法調試和無法真正理解的東西的框架,你將清楚的看到這一切是如何發(fā)生的。

很有可能下一份工作中,你并不能隨心所以地選擇框架開拓新項目。現(xiàn)實就是,在很多高價值,關鍵業(yè)務的 PHP 工作中均使用現(xiàn)有應用。 并且該應用程序是否構建在當前令人舒爽的 Laravel 或 Symfony 等流行框架中,亦或是陳舊過時的 CodeIgniter 或者 FuelPHP 中,更有甚者它可能廣泛出現(xiàn)在令人沮喪的  “面向包含體系結構” 的傳統(tǒng)的 PHP 應用 之中,所以框架開發(fā)會在將來你所面臨的任何 PHP 項目中助你一臂之力。

上古時代, 因為 某些系統(tǒng) 不得不解釋分發(fā) HTTP 請求,發(fā)送 HTTP 響應,管理依賴關系,無框架開發(fā)就是痛苦的鏖戰(zhàn)。缺乏行業(yè)標準必然意味著,框架中的這些組件高度耦合 。如果你從無框架開始,你終將難逃自建框架的命運。

時至今日,幸虧有 PHP-FIG 完成所有的自動加載和交互工作,無框架開發(fā)并非讓你白手起家。各色供應商都有這么多優(yōu)秀的可交互的軟件包。把他們組合起來容易得超乎你的想象!

PHP 是如何工作的?

在做其他事之前,搞清楚 PHP 如何與外界溝通是非常重要的。

PHP 以請求 / 響應為周期運行服務端應用程序。與你的應用程序的每一次交互——無論是來自瀏覽器,命令行還是 REST API ——都是作為請求進入應用程序的。 當接收到請求以后:

  1. 程序開始啟動;
  2. 開始處理請求;
  3. 產(chǎn)生響應;
  4. 接著,響應返回給產(chǎn)生請求的相應客戶端;
  5. 最后程序關閉。

每一個 請求都在重復以上的交互。

前端控制器

用這些知識把自己武裝起來以后,就可以先從我們的前端控制器開始編寫程序了。前端控制器是一個 PHP 文件,它處理程序的每一個請求。控制器是請求進入程序后遇到的第一個 PHP 文件,并且(本質上)也是響應走出你應用程序所經(jīng)過的最后一個文件。

我們使用經(jīng)典的 Hello, world! 作為例子來確保所有東西都正確連接上,這個例子由 PHP 的內(nèi)置服務器  驅動。在你開始這樣做之前,請確保你已經(jīng)安裝了 PHP7.1 或者更高版本。

創(chuàng)建一個含有 public 目錄的項目,然后在該目錄里面創(chuàng)建一個index.php 文件,文件里面寫入如下代碼:

  1. <?php 
  2. declare(strict_types=1); 
  3.  
  4. echo 'Hello, world!'

注意,這里我們聲明了使用嚴格模式 —— 作為最佳實踐,你應該在應用程序的 每個 PHP 文件的開頭 都這樣做。因為對從你后面來的開發(fā)者來說類型提示對 調試和清晰的交流意圖很重要 。

使用命令行(比如 macOS 的終端)切換到你的項目目錄并啟動 PHP 的內(nèi)置服務器。

 
  1. php -S localhost:8080 -t public

現(xiàn)在,在瀏覽器中打開 http://localhost:8080/ 。是不是成功地看到了 "Hello, world!" 輸出?

很好。接下來我們可以開始進入正題了!

自動加載與第三方包

當你第一次使用 PHP 時,你可能會在你的程序中使用 includes 或 requires 語句來從其他 PHP 文件導入功能和配置。 通常,我們會避免這么干,因為這會使得其他人更難以遵循你的代碼路徑和理解依賴在哪里。這讓調試成為了一個 真正的 噩夢。

解決辦法是使用自動加載(autoloading)。 自動加載的意思是:當你的程序需要使用一個類, PHP 在調用該類的時候知道去哪里找到并加載它。雖然從 PHP 5 開始就可以使用這個特性了, 但是得益于 PSR-0 ( 自動加載標準,后來被 PSR-4 取代),其使用率才開始有真正的提升。

我們可以編寫自己的自動加載器來完成任務,但是由于我們將要使用的管理第三方依賴的  Composer 已經(jīng)包含了一個完美的可用的自動加載器,那我們用它就行了。

確保你已經(jīng)在你的系統(tǒng)上 安裝 了 Composer。然后為此項目初始化 Composer:

  1. composer init 

這條命令通過交互式引導你創(chuàng)建 composer.json 配置文件。 一旦文件創(chuàng)建好了,我們就可以在編輯器中打開它然后向里面寫入 autoload 字段,使他看起來像這個樣子(這確保了自動加載器知道從哪里找到我們項目中的類):

  1.     "name""kevinsmith/no-framework"
  2.     "description""An example of a modern PHP application bootstrapped without a framework."
  3.     "type""project"
  4.     "require": {}, 
  5.     "autoload": { 
  6.         "psr-4": { 
  7.             "ExampleApp\\": "src/" 
  8.         } 
  9.     } 

現(xiàn)在為此項目安裝 composer,它引入了依賴(如果有的話),并為我們創(chuàng)建好了自動加載器:

  1. composer install 

更新 public/index.php 文件來引入自動加載器。在理想情況下,這將是你在程序當中使用的少數(shù)『包含』語句之一。

  1. <?php 
  2. declare(strict_types=1); 
  3.  
  4. require_once dirname(__DIR__) . '/vendor/autoload.php'
  5.  
  6. echo 'Hello, world!'

此時如果你刷新瀏覽器,你將不會看到任何變化。因為自動加載器沒有修改或者輸出任何數(shù)據(jù),所以我們看到的是同樣的內(nèi)容。讓我們把 Hello, world! 這個例子移動到一個已經(jīng)自動加載的類里面看看它是如何運作的。

在項目根目錄創(chuàng)建一個名為 src 的目錄,然后在里面添加一個叫 HelloWorld.php 的文件,寫入如下代碼:

  1. <?php 
  2. declare(strict_types=1); 
  3.  
  4. namespace ExampleApp; 
  5.  
  6. class HelloWorld 
  7.     public function announce(): void 
  8.     { 
  9.         echo 'Hello, autoloaded world!'
  10.     } 

現(xiàn)在到 public/index.php 里面用  HelloWorld 類的 announce 方法替換掉 echo 語句。

 
  1. // ... 
  2.  
  3. require_once dirname(__DIR__) . '/vendor/autoload.php'
  4.  
  5. $helloWorld = new \ExampleApp\HelloWorld(); 
  6. $helloWorld->announce(); 

刷新瀏覽器查看新的信息!

什么是依賴注入?

依賴注入是一種編程技術,每個依賴項都供給它需要的對象,而不是在對象外獲得所需的信息或功能。

舉個例子,假設應用中的類方法需要從數(shù)據(jù)庫中讀取。為此,你需要一個數(shù)據(jù)庫連接。常用的技術就是創(chuàng)建一個全局可見的新連接。

  1. class AwesomeClass 
  2.     public function doSomethingAwesome() 
  3.     { 
  4.         $dbConnection = return new \PDO( 
  5.             "{$_ENV['type']}:host={$_ENV['host']};dbname={$_ENV['name']}"
  6.             $_ENV['user'], 
  7.             $_ENV['pass'
  8.         ); 
  9.  
  10.         // Make magic happen with $dbConnection 
  11.     } 

但是這樣做顯得很亂,它把一個并非屬于這里的職責置于此地---創(chuàng)建一個 數(shù)據(jù)庫連接對象 , 檢查憑證 , 還有 處理一些連接失敗的問題---它會導致應用中出現(xiàn) 大量  重復代碼。如果你嘗試對這個類進行單元測試,會發(fā)現(xiàn)根本不可行。這個類和應用環(huán)境以及數(shù)據(jù)庫高度耦合。

相反,為何不一開始就搞清楚你的類需要什么?我們只需要首先將 “PDO” 對象注入該類即可。

  1. class AwesomeClass 
  2.     private $dbConnection;  
  3.     public function __construct(\PDO $dbConnection) 
  4.     { 
  5.         $this->dbConnection = $dbConnection; 
  6.     }  
  7.     public function doSomethingAwesome() 
  8.     { 
  9.         // Make magic happen with $this->dbConnection 
  10.     } 

這樣更簡潔清晰易懂,且更不易產(chǎn)生 Bug。通過類型提示和依賴注入,該方法可以清楚準確地聲明它要做的事情,而無需依賴外部調用去獲取。在做單元測試的時候,我們可以很好地模擬數(shù)據(jù)庫連接,并將其傳入使用。

依賴注入容器 是一個工具,你可以圍繞整個應用程序來處理創(chuàng)建和注入這些依賴關系。容器并不需要能夠使用依賴注入技術,但隨著應用程序的增長并變得更加復雜,它將大有裨益。

我們將使用 PHP 中最受歡迎的 DI 容器之一:名副其實的 PHP-DI(值得推薦的是它文檔中的 依賴注入另解 可能會對讀者有所幫助)

依賴注入容器

現(xiàn)在我們已經(jīng)安裝了 Composer ,那么安裝 PHP-DI 就輕而易舉了,我們繼續(xù)回到命令行來搞定它。

  1. composer require php-di/php-di 

修改 public/index.php 用來配置和構建容器。

  1. // ... 
  2.  
  3. require_once dirname(__DIR__) . '/vendor/autoload.php'
  4.  
  5. $containerBuilder = new \DI\ContainerBuilder(); 
  6. $containerBuilder->useAutowiring(false); 
  7. $containerBuilder->useAnnotations(false); 
  8. $containerBuilder->addDefinitions([ 
  9.     \ExampleApp\HelloWorld::class => \DI\create(\ExampleApp\HelloWorld::class) 
  10. ]); 
  11.  
  12. $container = $containerBuilder->build(); 
  13.  
  14. $helloWorld = $container->get(\ExampleApp\HelloWorld::class); 
  15. $helloWorld->announce(); 

沒啥大不了的。它仍是一個單文件的簡單示例,你很容易能看清它是怎么運行的。

迄今為止, 我們只是在 配置容器 ,所以我們必須 顯式地聲明依賴關系 (而不是使用 自動裝配 或 注解),并且從容器中檢索 HelloWorld 對象。

小貼士:自動裝配在你開始構建應用程序的時候是一個很不錯的特性,但是它隱藏了依賴關系,難以維護。 很有可能在接下里的歲月里, 另一個開發(fā)者在不知情的狀況下引入了一個新庫,然后就造就了多個庫實現(xiàn)一個單接口的局面,這將會破壞自動裝配,導致一系列讓接手者很容易忽視的的不可見的問題。

盡量 引入命名空間,可以增加代碼的可讀性。

  1. <?php 
  2. declare(strict_types=1); 
  3.  
  4. use DI\ContainerBuilder; 
  5. use ExampleApp\HelloWorld; 
  6. use function DI\create
  7.  
  8. require_once dirname(__DIR__) . '/vendor/autoload.php'
  9.  
  10. $containerBuilder = new ContainerBuilder(); 
  11. $containerBuilder->useAutowiring(false); 
  12. $containerBuilder->useAnnotations(false); 
  13. $containerBuilder->addDefinitions([ 
  14.     HelloWorld::class => create(HelloWorld::class) 
  15. ]); 
  16.  
  17. $container = $containerBuilder->build(); 
  18.  
  19. $helloWorld = $container->get(HelloWorld::class); 
  20. $helloWorld->announce(); 

現(xiàn)在看來,我們好像是把以前已經(jīng)做過的事情再拿出來小題大做。

毋需煩心,當我們添加其他工具來幫助我們引導請求時,容器就有用武之地了。它會在適當?shù)臅r機下按需加載正確的類。

中間件

如果把你的應用想象成一個洋蔥,請求從外部進入,到達洋蔥中心,最后變成響應返回出去。那么中間件就是洋蔥的每一層。它接收請求并且可以處理請求。要么把請求傳遞到更里層,要么向更外層返回一個響應(如果中間件正在檢查請求不滿足的特定條件,比如請求一個不存在的路由,則可能發(fā)生這種情況)。

如果請求通過了所有的層,那么程序就會開始處理它并把它轉換為響應,中間件接收到響應的順序與接收到請求的順序相反,并且也能對響應做修改,然后再把它傳遞給下一個中間件。

下面是一些中間件用例的閃光點:

  • 在開發(fā)環(huán)境中調試問題
  • 在生產(chǎn)環(huán)境中優(yōu)雅的處理異常
  • 對傳入的請求進行頻率限制
  • 對請求傳入的不支持資源類型做出響應
  • 處理跨域資源共享(CORS)
  • 將請求路由到正確的處理類

那么中間件是實現(xiàn)這些功能的唯一方式嗎?當然不是。但是中間件的實現(xiàn)使得你對請求 / 響應這個生命周期的理解更清晰。這也意味著你調試起來更簡單,開發(fā)起來更快速。

我們將從上面列出的最后一條用例,也就是路由,當中獲益。

路由

路由依靠傳入的請求信息來確定應當由哪個類來處理它。(例如 URI  /products/purple-dress/medium 應該被  ProductDetails::class類接收處理,同時 purple-dress 和 medium 作為參數(shù)傳入)

在范例應用中,我們將使用流行的 FastRoute 路由,基于 PSR-15兼容的中間件實現(xiàn)。

中間件調度器

為了讓我們的應用可以和 FastRoute 中間件---以及我們安裝的其他中間件協(xié)同工作---我們需要一個中間件調度器。

PSR-15是為中間件和調度器定義接口的中間件標準(在規(guī)范中又稱“請求處理器”),它允許各式各樣的中間件和調度器互相交互。我們只需選擇兼容 PSR-15 的調度器,這樣就可以確保它能和任何兼容 PSR-15 的中間件協(xié)同工作。

我們先安裝一個 Relay 作為調度器。

  1. composer require relay/relay:2.x@dev 

而且根據(jù) PSR-15 的中間件標準要求實現(xiàn)可傳遞 兼容 PSR-7 的 HTTP 消息, 我們使用 Zend Diactoros 作為 PSR-7 的實現(xiàn)。

  1. composer require zendframework/zend-diactoros 

我們用 Relay 去接收中間件。

  1. // ... 
  2.  
  3. use DI\ContainerBuilder; 
  4. use ExampleApp\HelloWorld; 
  5. use Relay\Relay; 
  6. use Zend\Diactoros\ServerRequestFactory; 
  7. use function DI\create
  8.  
  9. // ... 
  10.  
  11. $container = $containerBuilder->build(); 
  12.  
  13. $middlewareQueue = []; 
  14.  
  15. $requestHandler = new Relay($middlewareQueue); 
  16. $requestHandler->handle(ServerRequestFactory::fromGlobals()); 

我們在第 16 行使用 ServerRequestFactory::fromGlobals()  把 創(chuàng)建新請求的必要信息合并起來 然后把它傳給 Relay。 這正是 Request 進入我們中間件堆棧的起點。

現(xiàn)在我們繼續(xù)添加 FastRoute 和請求處理器中間件。 ( FastRoute 確定請求是否合法,究竟能否被應用程序處理,然后請求處理器發(fā)送 Request 到路由配置表中已注冊過的相應處理程序中)

  1. composer require middlewares/fast-route middlewares/request-handler 

然后我們給 Hello, world! 處理類定義一個路由。我們在此使用 /hello 路由來展示基本 URI 之外的路由。

  1. // ... 
  2.  
  3. use DI\ContainerBuilder; 
  4. use ExampleApp\HelloWorld; 
  5. use FastRoute\RouteCollector; 
  6. use Middlewares\FastRoute; 
  7. use Middlewares\RequestHandler; 
  8. use Relay\Relay; 
  9. use Zend\Diactoros\ServerRequestFactory; 
  10. use function DI\create
  11. use function FastRoute\simpleDispatcher; 
  12.  
  13. // ... 
  14.  
  15. $container = $containerBuilder->build(); 
  16.  
  17. $routes = simpleDispatcher(function (RouteCollector $r) { 
  18.     $r->get('/hello', HelloWorld::class); 
  19. }); 
  20.  
  21. $middlewareQueue[] = new FastRoute($routes); 
  22. $middlewareQueue[] = new RequestHandler(); 
  23.  
  24. $requestHandler = new Relay($middlewareQueue); 
  25. $requestHandler->handle(ServerRequestFactory::fromGlobals()); 

為了能運行,你還需要修改 HelloWorld 使其成為一個可調用的類, 也就是說 這里類可以像函數(shù)一樣被隨意調用.

  1. // ...  
  2. class HelloWorld 
  3.     public function __invoke(): void 
  4.     { 
  5.         echo 'Hello, autoloaded world!'
  6.         exit; 
  7.     } 

(注意在魔術方法 __invoke() 中加入exit;。 我們只需1秒鐘就能搞定--只是不想讓你遺漏這個事)

現(xiàn)在打開 http://localhost:8080/hello ,開香檳吧!

萬能膠水

睿智的讀者可能很快看出,雖然我們?nèi)耘f囿于配置和構建 DI 容器的藩籬之中,容器現(xiàn)在實際上對我們毫無用處。調度器和中間件在沒有它的情況下也一樣運作。

那它何時才能發(fā)揮威力?

嗯,如果---在實際應用程序中總是如此---HelloWorld類具有依賴關系呢?

我們來講解一個簡單的依賴關系,看看究竟發(fā)生了什么。

  1. // ...  
  2. class HelloWorld
  3.  
  4.     private $foo;  
  5.     public function __construct(string $foo) 
  6.     { 
  7.         $this->foo = $foo; 
  8.     }  
  9.     public function __invoke(): void 
  10.     { 
  11.         echo "Hello, {$this->foo} world!"
  12.         exit; 
  13.     } 

刷新瀏覽器..

WOW!

看下這個 ArgumentCountError.

發(fā)生這種情況是因為 HelloWorld 類在構造的時候需要注入一個字符串才能運行,在此之前它只能等著。  正是容器要幫你解決的痛點。
我們在容器中定義該依賴關系,然后將容器傳給 RequestHandler 去 解決這個問題.

  1. // ...  
  2. use Zend\Diactoros\ServerRequestFactory; 
  3. use function DI\create
  4. use function DI\get; 
  5. use function FastRoute\simpleDispatcher; 
  6.  
  7. // ...  
  8. $containerBuilder->addDefinitions([ 
  9.     HelloWorld::class => create(HelloWorld::class) 
  10.         ->constructor(get('Foo')), 
  11.     'Foo' => 'bar' 
  12. ]);  
  13. $container = $containerBuilder->build(); 
  14.  
  15. // ...  
  16. $middlewareQueue[] = new FastRoute($routes); 
  17. $middlewareQueue[] = new RequestHandler($container);  
  18. $requestHandler = new Relay($middlewareQueue); 
  19. $requestHandler->handle(ServerRequestFactory::fromGlobals()); 

嗟夫!當刷新瀏覽器的時候, "Hello, bar world!"將映入你的眼簾!

正確地發(fā)送響應

是否還記得我之前提到過的位于 HelloWorld 類中的 exit 語句?

當我們構建代碼時,它可以讓我們簡單粗暴的獲得響應,但是它絕非輸出到瀏覽器的最佳選擇。這種粗暴的做法給 HelloWorld 附加了額外的響應工作---其實應該由其他類負責的---它會過于復雜的發(fā)送正確的頭部信息和 狀態(tài)碼,然后立刻退出了應用,使得 HelloWorld 之后 的中間件也無機會運行了。

記住,每個中間件都有機會在 Request 進入我們應用時修改它,然后 (以相反的順序) 在響應輸出時修改響應。 除了 Request 的通用接口, PSR-7 同樣也定義了另外一種 HTTP 消息結構,以輔助我們在應用運行周期的后半部分之用:Response。(如果你想真正了解這些細節(jié),請閱讀 HTTP 消息以及什么讓 PSR-7 請求和響應標準如此之好。)

修改 HelloWorld 返回一個 Response

  1. // ...  
  2. namespace ExampleApp;  
  3. use Psr\Http\Message\ResponseInterface;  
  4. class HelloWorld
  5.  
  6.     private $foo;  
  7.     private $response;  
  8.     public function __construct( 
  9.         string $foo, 
  10.         ResponseInterface $response 
  11.     ) { 
  12.         $this->foo = $foo; 
  13.         $this->response = $response; 
  14.     } 
  15.  
  16.     public function __invoke(): ResponseInterface 
  17.     { 
  18.         $response = $this->response->withHeader('Content-Type''text/html'); 
  19.         $response->getBody() 
  20.             ->write("<html><head></head><body>Hello, {$this->foo} world!</body></html>"); 
  21.  
  22.         return $response; 
  23.     } 

然后修改容器給 HelloWorld 提供一個新的 Response 對象。

  1. // ...  
  2. use Middlewares\RequestHandler; 
  3. use Relay\Relay; 
  4. use Zend\Diactoros\Response; 
  5. use Zend\Diactoros\ServerRequestFactory; 
  6. use function DI\create 
  7. // ...  
  8. $containerBuilder->addDefinitions([ 
  9.     HelloWorld::class => create(HelloWorld::class) 
  10.         ->constructor(get('Foo'), get('Response')), 
  11.     'Foo' => 'bar'
  12.     'Response' => function() { 
  13.         return new Response(); 
  14.     }, 
  15. ]); 
  16.  
  17. $container = $containerBuilder->build();  
  18. // ... 

如果你現(xiàn)在刷新頁面,會發(fā)現(xiàn)一片空白。我們的應用正在從中間件調度器返回正確的 Response 對象,但是... 腫么回事?

它啥都沒干,就這樣。

我們還需要一件東西來包裝下:發(fā)射器。發(fā)射器位于應用程序和 Web 服務器(Apache,nginx等)之間,將響應發(fā)送給發(fā)起請求的客戶端。它實際上拿到了 Response 對象并將其轉化為 服務端 API 可理解的信息。

好消息! 我們已經(jīng)用來封裝請求的 Zend Diactoros 包同樣也內(nèi)置了發(fā)送 PSR-7 響應的發(fā)射器。

值得注意的是,為了舉例,我們只是對發(fā)射器的使用小試牛刀。雖然它們可能會更復雜點,真正的應用應該配置成自動化的流式發(fā)射器用來應對大量下載的情況, Zend 博客展示了如何實現(xiàn)它

修改 public/index.php ,用來從調度器那里接收 Response ,然后傳給發(fā)射器。

  1. // ...  
  2. use Relay\Relay; 
  3. use Zend\Diactoros\Response; 
  4. use Zend\Diactoros\Response\SapiEmitter; 
  5. use Zend\Diactoros\ServerRequestFactory; 
  6. use function DI\create 
  7. // ...  
  8. $requestHandler = new Relay($middlewareQueue); 
  9. $response = $requestHandler->handle(ServerRequestFactory::fromGlobals());  
  10. $emitter = new SapiEmitter(); 
  11. return $emitter->emit($response); 

刷新瀏覽器,業(yè)務恢復了!這次我們用了一種更健壯的方式來處理響應。

以上代碼的第 15 行是我們應用中請求/響應周期結束的地方,同時也是 web 服務器接管的地方。

總結

現(xiàn)在你已經(jīng)獲得了現(xiàn)代化的 PHP 代碼。 僅僅 44 行代碼,在幾個被廣泛使用,經(jīng)過全面測試和擁有可靠互操作性的組件的幫助下,我們就完成了一個現(xiàn)代化 PHP 程序的引導。它兼容 PSR-4, PSR-7,PSR-11 以及 PSR-15,這意味著你可以使用自己選擇的其他任一供應商對這些標準的實現(xiàn),來構建自己的 HTTP 消息, DI 容器,中間件,還有中間件調度器。

我們深入理解了我們決策背后使用的技術和原理,但我更希望你能明白,在沒有框架的情況下,引導一個新的程序是多么簡單的一件事。或許更重要的是,我希望在有必要的時候你能更好的把這些技術運用到已有的項目中去。

你可以在 這個例子的 GitHub 倉庫 上免費 fork 和下載它。

如果你正在尋找更高質量的解耦軟件包資源,我衷心推薦你看看 Aura, 了不起的軟件包聯(lián)盟, Symfony 組件, Zend Framework 組件,Paragon 計劃的聚焦安全的庫, 還有這個 關于 PSR-15 中間件的清單.

如果你想把這個例子的代碼用到生產(chǎn)環(huán)境中, 你可能需要把路由和 容器定義 分離到它們各自的文件里面,以便將來項目復雜度提升的時候更好維護。我也建議 實現(xiàn) EmitterStack 來更好的處理文件下載以及其他的大量響應。 

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2024-06-14 08:00:46

2019-09-09 06:50:14

mv命令移動文件Linux

2025-07-30 01:45:00

2018-12-07 11:15:20

設置Windows 10命令

2010-08-16 10:10:22

SQL腳本

2021-08-17 10:04:42

CIOIT現(xiàn)代化科技公司

2010-05-07 14:38:47

Unix KDE

2012-04-11 10:16:22

綜合布線

2020-08-04 09:11:47

架構師垃圾代碼

2021-03-18 09:24:11

DrogonC++框架

2023-08-31 10:04:02

Astro 3.0前端

2022-07-26 06:57:07

數(shù)據(jù)管道端點API

2024-01-09 11:39:47

數(shù)字化轉型數(shù)字優(yōu)先企業(yè)

2023-12-07 11:38:25

2020-11-18 09:26:52

@property裝飾器代碼

2023-09-17 12:21:21

RemixNext.js

2021-07-09 05:25:48

CIO遺留系統(tǒng)現(xiàn)代化用戶體驗

2023-02-08 11:07:56

數(shù)字時代數(shù)字運營模式

2023-06-25 09:04:12

數(shù)字企業(yè)架構EA
點贊
收藏

51CTO技術棧公眾號

久久国产欧美日韩精品| 日韩深夜福利| 亚洲国产欧美日韩另类综合 | 在线视频欧美性高潮| 欧美成人福利在线观看| 性欧美ⅴideo另类hd| av一本久道久久综合久久鬼色| 日韩免费观看在线观看| 老熟妇高潮一区二区三区| 国产精品极品| 欧美日本乱大交xxxxx| 成人中文字幕在线播放| 91在线视频免费看| 成人aa视频在线观看| 国产精品日日做人人爱| 精品一区在线视频| 88国产精品视频一区二区三区| 日韩成人黄色av| 手机av在线网站| 精品成人av| 亚洲一卡二卡三卡四卡| 亚洲 国产 欧美一区| 午夜成人免费影院| 国产精品一区二区在线看| 国产suv精品一区二区| 国产在线观看99| 97视频精品| 亚洲图片欧洲图片av| 你懂得在线视频| 久久伊人影院| 欧美日韩国产首页| 欧美伦理视频在线观看| 性国裸体高清亚洲| 激情亚洲一区二区三区四区| 国产精品一二三在线观看| 午夜国产福利在线| 国产拍揄自揄精品视频麻豆| 精品综合在线| 欧美 日韩 国产 成人 在线 91| 激情五月播播久久久精品| 国产精品伦子伦免费视频| 老熟妇一区二区三区| 国产精品五区| 2019最新中文字幕| 日韩免费在线视频观看| 精品999日本| 欧美激情日韩图片| 精品无码av在线| 欧美一区亚洲| 欧美日韩爱爱视频| 久久这里只有精品国产| 国内精品福利| 国产做受高潮69| 久久婷婷综合国产| 亚洲国产一区二区三区高清| 久久久中文字幕| 日韩黄色a级片| 国产日韩专区| 日韩免费黄色av| 欧美日韩在线视频播放| 日本在线不卡一区| 国产精品一区二区久久精品| 亚洲在线免费观看视频| 国产一区二区三区国产| 99视频在线播放| 亚洲男女视频在线观看| 99热国产精品| 青青草久久网络| 日本天堂在线观看| 亚洲激情图片小说视频| 国产片侵犯亲女视频播放| 91在线超碰| 欧美影视一区在线| 91精品999| 日韩精品视频一区二区三区| 亚洲国内精品视频| 51妺嘿嘿午夜福利| 亚欧美无遮挡hd高清在线视频 | 永久久久久久久| 国产精品vip| 欧美专区国产专区| 亚洲视频一区在线播放| 国产精品一区二区在线播放| 国产女人水真多18毛片18精品| 色视频在线看| 亚洲欧洲无码一区二区三区| 亚洲国产一二三精品无码 | 久草福利在线| 中文字幕亚洲在| 岛国大片在线播放| 国产超碰精品| 日韩三级在线免费观看| 韩国无码一区二区三区精品| 欧美一站二站| 欧美极品欧美精品欧美视频| 无码人妻精品一区二区50| 国模一区二区三区白浆| 精品网站在线看| 日p在线观看| 精品福利视频导航| 中文字幕丰满乱码| 日韩三级视频| 欧美日韩国产二区| 中文字幕一区二区三区人妻四季| 国产成人激情av| 日本亚洲欧洲精品| mm视频在线视频| 欧美精品乱人伦久久久久久| 熟女人妻在线视频| 欧美久久影院| 国产精品入口免费视| 四虎永久在线精品免费网址| 中文字幕中文在线不卡住| 日韩少妇内射免费播放| 成人51免费| 国产一区二区免费| 日韩av一二三区| 国产精品一区二区你懂的| 欧洲精品久久| 蜜桃视频m3u8在线观看| 日韩区在线观看| 人人艹在线视频| 久久久亚洲人| 久久精品国产精品青草色艺| 免费av不卡在线观看| 欧美军同video69gay| 午夜理伦三级做爰电影| 在线视频精品| 国产精品高清一区二区三区| 大片免费在线观看| 欧美性猛交xxxx乱大交退制版| 狠狠人妻久久久久久综合蜜桃| 欧美精品91| 亚洲www在线观看| 午夜在线免费观看视频| 欧洲国内综合视频| 熟女少妇内射日韩亚洲| 男人的天堂亚洲| 麻豆av一区二区三区久久| av影视在线看| 亚洲成人久久久久| 国产午夜精品一区二区理论影院| 国产精品一品视频| 亚洲精品少妇一区二区| 精品国产不卡一区二区| 久久久成人av| 精品人妻一区二区三区换脸明星| 亚洲欧美激情在线| 国产一级片中文字幕| 欧美有码视频| 不卡视频一区二区| 2001个疯子在线观看| 精品国产一区a| 日韩乱码在线观看| 91视频国产资源| 久久九九国产视频| 波多野结衣在线观看一区二区| 国产精品劲爆视频| 成人在线免费看黄| 精品裸体舞一区二区三区| 国产精彩视频在线| 26uuu亚洲| 一级在线免费视频| 91精品综合久久久久久久久久久 | 亚洲a级精品| 国产97色在线|日韩| 黄色av网站在线| 欧美日韩高清一区| 青青青在线免费观看| 成人看片黄a免费看在线| 黄色一级片播放| 日韩精品一区二区久久| 91深夜福利视频| www555久久| 亚洲性生活视频| 国产精品乱码久久久| 艳妇臀荡乳欲伦亚洲一区| 99久久人妻无码中文字幕系列| 老司机午夜精品视频| 中文网丁香综合网| 成人在线视频你懂的| 日韩av色在线| 大地资源网3页在线观看| 亚洲韩国欧洲国产日产av| 波多野结衣网站| 亚洲精品一二三四区| 黄色短视频在线观看| 国内成人精品2018免费看| 日日摸日日碰夜夜爽无码| 欧美日韩国产传媒| 成人高清在线观看| 免费观看成人性生生活片 | 国产在线综合网| 欧美国产日韩精品免费观看| 超碰人人cao| 久久久777| 激情五月六月婷婷| 欧美日韩国产在线观看网站| 97超级碰碰| 日韩不卡在线| 91精品国产91久久| 91麻豆一二三四在线| 亚洲午夜久久久影院| 亚洲第一页视频| 欧美日韩精品欧美日韩精品一综合| 国产在线视频99| 日韩一区中文字幕| www.黄色在线| 99精品桃花视频在线观看| 中文字幕一区二区三区四| 日韩精品亚洲一区二区三区免费| 黄色成人在线免费观看| 久久亚洲成人| 精品一区二区国产| 在线精品自拍| 91视频8mav| 日本a人精品| 国产v综合ⅴ日韩v欧美大片 | 亚洲高清久久久| 日本黄色录像视频| 中文字幕乱码一区二区免费| 在线免费观看成年人视频| 成人性生交大片免费看中文| 亚洲欧美天堂在线| 奇米四色…亚洲| 欧美一级黄色片视频| 亚洲精选在线| 老司机激情视频| 午夜激情久久| 国产91av视频在线观看| 精品视频99| 日产精品久久久一区二区| 亚洲专区视频| 欧美日韩亚洲在线| 欧美调教在线| 极品尤物一区二区三区| 国产精品视屏| 精品产品国产在线不卡| 88久久精品| 成人午夜影院在线观看| 综合激情网...| 操一操视频一区| 波多野结衣在线一区二区| 99精品国产高清一区二区| 一本色道69色精品综合久久| 亚洲一区二区三区四区在线播放 | 精品国产乱子伦一区| 国产ts人妖调教重口男| 日韩精品一区在线观看| 亚洲av无码片一区二区三区| 欧美成人一区二区三区在线观看| 成人高潮片免费视频| 精品动漫一区二区三区在线观看| 超碰免费在线97| 亚洲国产成人91精品| 色鬼7777久久| 在线观看91久久久久久| 日本天堂在线观看| 欧美裸身视频免费观看| 97在线视频免费观看完整版| 97人人做人人爱| 欧美日韩国产v| 国产一区玩具在线观看| 成人97精品毛片免费看| 国产精品久久7| 亚洲午夜久久| 亚洲成人a**址| 女人香蕉久久**毛片精品| 国产天堂视频在线观看| 国产亚洲在线观看| 色一情一乱一伦一区二区三区日本 | 成人av综合在线| 香蕉网在线播放| 国产精品嫩草久久久久| 激情四射综合网| 疯狂做受xxxx欧美肥白少妇| av手机天堂网| 日韩午夜激情视频| 三级视频在线播放| 日韩中文字幕欧美| 91av久久| 国产精品入口日韩视频大尺度| 亚洲精品不卡在线观看 | 99久久视频| 国产一二三在线视频| 天堂一区二区在线免费观看| 伊人国产精品视频| 91在线视频播放地址| 欧美风情第一页| 欧美日韩在线视频观看| 国产尤物视频在线观看| 日韩美女av在线| 成人ww免费完整版在线观看| 97av在线影院| 精品视频在线观看网站| 欧美精品一区二区三区久久| 亚洲成av人片乱码色午夜| 91免费视频网站在线观看| 国产真实乱子伦精品视频| 少妇一级淫免费观看| 国产精品人成在线观看免费| 国产无码精品一区二区| 欧美色手机在线观看| 天堂av一区二区三区| av不卡免费看| 午夜精品久久久久久久久久久久| 97天天综合网| 91网站在线看| 欧美精品中文字幕亚洲专区| 四虎免费在线观看视频| 久久在线精品| 国产69视频在线观看| 中文字幕视频一区二区三区久| 久久精品视频1| 欧美成人bangbros| 麻豆电影在线播放| 国产精品久久精品| 香蕉视频一区二区三区| 久久综合久久网| 国产乱人伦偷精品视频免下载 | 91精品国产沙发| 日韩精品视频一区二区三区| 亚洲日本欧美在线| 日韩中文字幕91| theav精尽人亡av| 亚洲妇熟xx妇色黄| 亚洲精品久久久蜜桃动漫| 久久精品国产一区| 亚洲精品大全| 一区二区三区欧美在线| 日本91福利区| 夫妇交换中文字幕| 一本高清dvd不卡在线观看| 午夜性色福利影院| 97久久久久久| 偷拍亚洲色图| 亚洲中文字幕无码中文字| 波多野结衣中文字幕一区 | 国产日韩亚洲精品| 狠狠色丁香久久综合频道| 亚洲丝袜在线观看| 亚洲综合一区二区| 亚洲免费一级片| 久久久久久亚洲| 日本成人中文| 少妇人妻互换不带套| 久久精品一区二区三区av| 天天干天天色综合| 国产亚洲欧美一区| 国产精品黄色片| 一区二区三区av在线| 精品一区二区久久久| 精品国产视频一区二区三区 | 免费一级在线观看播放网址| 欧美一区二三区| 教室别恋欧美无删减版| 亚洲一区在线不卡| 亚洲三级在线免费观看| 国产高清视频免费| 高清亚洲成在人网站天堂| 亲子伦视频一区二区三区| 欧美 国产 小说 另类| 欧美韩国日本综合| 国产视频在线免费观看| 欧美激情视频一区二区三区不卡| 国产成人福利av| 久久精品香蕉视频| 成人免费一区二区三区视频| 性生交大片免费看女人按摩| 午夜精品久久久久久久99热浪潮| 中文有码一区| 波多野结衣国产精品| 亚洲电影第三页| 国产视频三级在线观看播放| 成人在线中文字幕| 99伊人成综合| 久久久久亚洲AV成人无在 | 亚洲三区在线观看无套内射| 国产成人精品国内自产拍免费看 | 林ゆな中文字幕一区二区| 精品一卡二卡三卡| 一区在线中文字幕| 偷拍自拍在线| 成人免费福利视频| 99综合在线| 亚洲国产123| 日韩hd视频在线观看| 国产成人久久精品麻豆二区| 国产视频在线观看网站| 久久久777精品电影网影网| 国产精品自偷自拍| 欧美亚洲第一页| 在线成人直播| 人人妻人人澡人人爽| 精品国产欧美一区二区| 福利视频一区| 国产精品自拍片| 亚洲乱码国产乱码精品精可以看| 欧美偷拍视频| 成人xxxxx色|