背景
一次無意的訪問,點擊到了一個專門做PHP性能測驗的網站,看這里PHP Benchmarks,
在里面發現了框架性能測驗的結果,發現Laravel的框架性能盡然是最低的,瞬間受到了一萬點的暴擊,誰讓最近一直用Laravel開發專案的呢,
說到底還是Laravel好用呀,方便不說,各方面支持的也不錯,業務方面做的也是內部系統,哪怕性能慢點,也可以用前后端分離、負載均衡等手段解決掉,大體上也是夠用,
不過,作為一個開發人員,理想還是要有的,這時就在想能不能采取Laravel框架的優點,用到什么就裝什么,去掉一些請求到回應之間用不到的組件,精簡框架,
之前也熟讀過Laravel的原始碼,知道它的底層用的是Symfony的組件,畢竟沒必要重復的造輪子,那么我們的框架之旅也將基于Symfony組件,,,
目錄
一、Composer運行機制
二、框架前期準備
三、HttpFoundation組件封裝Request、Response
四、路由處理
五、控制器處理相應功能(C)
六、分離模板(V)
七、分離模型(M)
八、剝離核心代碼
九、優化框架
十、依賴注入(Dependency Injection)
正文
一、Composer運行機制
Composer的使用最關鍵的得益于PHP標準規范的出現,特別是其中的psr4,自動加載規范,規范了如何指定檔案路徑從而自動加載類定義,以及自動加載檔案的位置,
既然講到php檔案的加載,我們就要聊一聊PHP的加載機制了,
在早前時,加載檔案用的都是include、require,但這種加載有很大的局限性,相信同學們都知道,無論用到用不到都要加載大量的檔案,相當繁瑣,
于是就出現了autoload加載機制,它可以實作懶加載,
function __autoload($class)
{
require_once ($class.".php");
}
當程式參考了未加載的類,就會自動呼叫__autoload方法,只要維護了__autoload方法,就可以懶加載檔案,
但這里有一個很大的問題,就是程式中只能定義一次__autoload,這就需要花大盡力在__autoload中維護檔案和空間的對應關系,特別是在大型專案,多人合作中更是繁瑣,
而解決這個問題就是SPL Autoload,
SPL Autoload:__autoload呼叫堆疊,
怎么理解這個堆疊呢,舉個例子,
現有的框架比如ThinkPHP、Laravel等都有一個vendor目錄,用于存放第三方庫,現在vendor下有兩個庫,
monolog 處理系統日志
guzzlehttp 處理HTTP
當程式參考這兩個庫的命名空間,并呼叫monolog、guzzlehttp下面的類時,發現呼叫的類檔案都能被找到,
這主要原理是monolog、guzzlehttp都自定義了類似autoload的方法,然后用spl_autoload_register將方法注冊到了SPL堆疊中,
這樣的話,當程式呼叫類的時候,就會統一到SPL堆疊中尋找注冊到堆疊中的autoload方法,并加載相應的檔案,
以上就是php加載檔案的方式,下面就用實戰談一談composer的運行機制,
創建composer專案
# mkdir phoenix
# cd phoenix
composer init
phoenix是接下來搭建的框架名,

創建成功后,發現當前檔案夾下會生成一個composer.json檔案,里面是剛寫入的內容,
composer dump

tree后,就會發現多了一個vendor的目錄,里面的autoload.php以及composer檔案夾下檔案就是整個框架的加載核心,
接下來看一遍這些檔案,
在整個框架中,第一行必然要參考 vendor/autoload.php 檔案,畢竟這是加載核心,那么就從autoload.php看起,
# autoload.php
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit599fa618dd1395bdde5fc3a08ff3e4e6::getLoader();
只呼叫了autoload_real.php里面的getLoader()方法,
#autoload_real.php 精簡后的代碼
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
#創建ClassLoader類
spl_autoload_register(array('ComposerAutoloaderInit599fa618dd1395bdde5fc3a08ff3e4e6', 'loadClassLoader'), true, true);
#初始化ClassLoader物件(主要就是將命名空間和檔案的映射寫入ClassLoader的屬性中)
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit599fa618dd1395bdde5fc3a08ff3e4e6', 'loadClassLoader'));
#loadClass方法(類似autoload方法)注冊到 SPL Autoload
$loader->register(true);
}
autoload_real.php 的作用就是引入ClassLoader類、初始化ClassLoader類,并注冊到SPL堆疊中,
ClassLoader類中有很多屬性,這些屬性的作用也很簡單:主要就是方便后面程式快速的通過命名空間找到它所映射的類檔案,
具體用到這些屬性的方法就在ClassLoader類中,
# ClassLoader.php
# 一個快速找到檔案的演算法,很有意思,感興趣的可以研究下
# 主要通過首字符找到命名空間以及長度,再根據命名空間以及長度找到檔案
private function findFileWithExtension($class, $ext)
{
......
}
那么ClassLoader類屬性里面的值是什么時候寫入的呢?
答案很簡單:當為專案安裝組件時,即composer require xxx時,會更新ClassLoader類的屬性值,也就是將命名空間和檔案地址做一個關聯,
接下來看看它的register方法,
# ClassLoader.php
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
看,其實很簡單,就是將loadClass注冊到SPL堆疊中,
那么現在就很清楚了,當程式使用了一個還未加載的類時,會呼叫什么方法?
當然是loadClass方法,再來看看loadClass方法,
# ClassLoader.php
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
根據方法的名稱就能看出它的功能:1、找到檔案 2、加載檔案,
總結一下Composer的運行機制:
**1、在composer require安裝時,更新ClassLoader類的屬性 **,
2、運行物件時(new \Test()),如果未加載就會執行loadClass(),通過首字符找到命名空間以及長度,再根據命名空間以及長度找到檔案,最后include檔案,
以上就是Composer的運行機制,接下來,就進入真正的框架搭建了,
二、框架前期準備
在正式進入搭建框架之前,先看下整體的架構圖以及一些前期準備,

整個架構跟Laravel、ThinkPHP等框架是差不多的,一次請求,一次回傳,一個入口,中間根據路由規則交給相應的控制器去執行,在控制器中處理資料以及視圖,
接下來做一些前期準備,進入phoenix專案,
# vi index.php 一個入口
ini_set('display_errors', 1); # 顯示錯誤
error_reporting(-1);
require_once __DIR__.'/vendor/autoload.php'; # 引入核心加載類
$name = $_GET['name'];
dump($name);
# dump()
composer require symfony/var-dumper # 類似var_dump,輸出的變數體驗更好些,
配置Nginx,訪問域名為:http://dev.phoenix.goods/?name=SexyPhoenix, 可以正常顯示SexyPhoenix,
三、HttpFoundation組件封裝Request、Response
現有的程式只是一個面向程序的代碼,一個簡單的請求,回應,
對于搭建web框架,這種痛苦寫法當然是要被舍棄的,OOP編程才是正路,
既然要面向物件編程,首先要做的就是對流程中的Request、Response進行封裝,而Symfony中專門的組件,
composer require symfony/http-foundation
HttpFoundation組件使用說明
改造代碼
# index.php
ini_set('display_errors', 1);
error_reporting(-1);
require_once __DIR__.'/vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$request = Request::createFromGlobals(); # 創建request物件
$name = $request->get('name', 'World'); # 獲取引數,可移入控制器或從模型得到資料
$response = new Response();
$response->setContent('<b>Hello '.$name.'</b>'); # 設定內容,可用view處理
$response->send(); # 回傳
下面來做一個簡單的分析,
$request = Request::createFromGlobals();
這一行代碼,是相當重要的,它從物件層面上處理了php的全域變數,例如 GET,POST,SESSION......,

這樣處理就可以輕易的從request物件中獲取所需要的資訊以及對請求頭等資訊的修改,
后期路由這些附加的資訊也是存在request的attributes屬性中,及其好用,
$response = new Response();
通過response物件,可以輕易的控制回傳的資訊,比如頭資訊的各種快取策略......
四、路由處理
從架構圖上看,接著就要處理路由了,
phoneix框架用了普遍的做法,統一index.php入口,
那么下面要做的就是如何將路由的附加引數和要處理的控制器進行映射,
對于路由一般框架都是通過配置來的,這里也一樣做成可配置,方便,
Yaml格式配置路由
在phoenix專案下,創建routes檔案夾,在routes下繼續創建web.yaml檔案,
dashboard:
path: /dashboard
defaults: {
_controller: 'App\Http\Controllers\DashboardController::index'
}
下載symfony的Config組件、Yaml組件、Routing組件,
composer require symfony/config
composer require symfony/yaml
composer require symfony/routing
Config組件使用說明
更新代碼
# index.php
ini_set('display_errors', 1);
error_reporting(-1);
require_once __DIR__.'/vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Loader\YamlFileLoader; # add
use Symfony\Component\Config\FileLocator; # add
$request = Request::createFromGlobals();
$fileLoader = new YamlFileLoader(new FileLocator(array(__DIR__))); # add
$collection = $fileLoader->load('routes/web.yaml'); # add
$name = $request->get('name', 'World');
$response = new Response();
$response->setContent('<b>Hello '.$name.'</b>');
$response->send();
dump($collection),可以看到回傳了路由的Collection物件,里面有定義的路由,

這個時候,框架只是得到了定義的路由,但還沒有和URL做映射,下面改造繼續,
URL和配置路由映射
ini_set('display_errors', 1);
error_reporting(-1);
require_once __DIR__.'/vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\RequestContext; # add
use Symfony\Component\Routing\Matcher\UrlMatcher; # add
$request = Request::createFromGlobals();
$fileLoader = new YamlFileLoader(new FileLocator(array(__DIR__)));
$collection = $fileLoader->load('routes/web.yaml');
#決議url
$context = new RequestContext(); # add
$context->fromRequest($request); # add
#初始化UrlMatcher
$matcher = new UrlMatcher($collection, $context); # add
#url和路由配置映射
$route = $matcher->match($request->getPathInfo()) # add
$name = $request->get('name', 'World');
$response = new Response();
$response->setContent('<b>Hello '.$name.'</b>');
$response->send();
繼續分析,
$context = new RequestContext();
$context->fromRequest($request);
context物件主要就是對url進行決議,現在的域名:http://dev.phoenix.goods/dashboard

既然決議出url的引數,就要用決議出的引數和配置中的路由做精準關聯了,初始化matcher,傳入路由配置和url物件,

得到url和配置中的路由的映射,
$route = $matcher->match($request->getPathInfo());

五、控制器處理相應功能(C)
在路由處理中,框架已經得到了路由和控制器的關聯關系,下面就要執行相應的控制器(上面的_controller值),
首先,在phoenix專案下,創建app/Http/Controllers/DashboardController.php(仿造Laravel的目錄結構),
# DashboardController.php
namespace App\Http\Controllers; # 注意這里App命名空間,自己定義,并沒有注冊到autoload
class DashboardController{
public function index()
{
echo 'Hello SexyPhoenix';
}
}
App命名空間是框架定義的,需要注冊后,才能用,打開專案的composer.json檔案,
# composer.json
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
composer dump-autoload # 更新命名空間
到這里,控制器的準備作業就做完了,接下來的問題就是如果利用得到的路由和控制器的映射關系去執行控制器,也就是下面的代碼,
App\Http\Controllers\DashboardController::index
其實也很簡單,就是用"::"分隔,得到兩個值,一個是類名,一個是方法名,再用php的call_user_func去執行,
但自己去寫可能過去粗暴,可用性低,在執行前,要先判斷DashboardController類是否存在,index方法是否存在,index方法的權限,是否是公共方法,以及各種引數等等,
自己去寫的話,會很麻煩,為了方便,繼續用symfony的組件,
composer require symfony/http-kernel
http-kernel組件,是框架的內核,很重要的組件,它提供了各種鉤子,及其方便框架擴展,也提供了控制器及其引數的“決議器”(這里需要了解下php的反射機制),
更新index.php代碼,
# index.php
......
use Symfony\Component\HttpKernel\Controller\ControllerResolver; # add
use Symfony\Component\HttpKernel\Controller\ArgumentResolver; # add
......
$route = $matcher->match($request->getPathInfo());
$request->attributes->add($route); # add 將路由映射關系寫入request物件的附加屬性中,
$controller = (new ControllerResolver())->getController($request); # add 處理控制器
$arguments = (new ArgumentResolver())->getArguments($request, $controller); # add 處理方法的引數
$response = call_user_func_array($controller, $arguments);
$response->send();
更新DashboardController.php代碼,
namespace App\Http\Controllers;
use Symfony\Component\HttpFoundation\Request; # add
use Symfony\Component\HttpFoundation\Response;# add
class DashboardController{
public function index(Request $request)
{
$name = $request->get('name', 'world'); # add
return new Response('Hello '.$name); # add
}
}
用http-kernel好處就是可以處理各種問題,比如Request作為引數注入,
訪問 http://dev.phoenix.goods/dashboard?name=SexyPhoenix, 得到 Hello SexyPhoenix,
http-kernel組件的使用說明
六、分離模板(V)
現在的框架只是簡單的輸出字串,在正式環境中當然不可能這么簡單,要能夠回傳正常的HTML頁面,
而復雜的HTML也不能放在控制器中處理,需要分離出來,單獨處理,Symfony為框架同樣提供了相關的組件,
composer require symfony/templating
Templating組件使用說明
處理框架的目錄結構,
在phoenix專案下,創建resources/views檔案夾,繼續在views下創建dashboard.php檔案,
# dashboard.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Phoenix</title>
<style>
html, body {
color: #000;
font-family: 'Raleway', sans-serif;
font-weight: 100;
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<div>
<h2>Hello, <b><?php echo $name?></b></h2>
<h3>your mailbox:<?php echo $email?></h3>
<h3>your github:<?php echo $github?></h3>
</div>
</body>
</html>
在app/Http/Controllers下創建Controller.php檔案,
# Controller.php
namespace App\Http\Controllers;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Templating\PhpEngine;
use Symfony\Component\Templating\TemplateNameParser;
use Symfony\Component\Templating\Loader\FilesystemLoader;
class Controller {
/**
* $templete 模板檔案
* $data 資料
*/
public function render($templete, array $data)
{
return new Response(
(new PhpEngine(
new TemplateNameParser(),
new FilesystemLoader(getcwd().'/resources/views/%name%')
))
->render($templete, $data)
);
}
}
改造DashboardController.php 代碼,
namespace App\Http\Controllers;
use Symfony\Component\HttpFoundation\Request;
class DashboardController extends Controller{ # 繼承Controller
public function index(Request $request)
{
$name = $request->get('name', 'world');
$data = https://www.cnblogs.com/SexyPhoenix/p/['name' => $name,
'email' => '[email protected]',
'github' => 'https://github.com/SexyPhoenix'
];
return $this->render('dashboard.php', $data);
}
}
訪問 http://dev.phoenix.goods/dashboard?name=SexyPhoenix, 頁面正常顯示,

七、分離模型(M)
分離完模板后,架構的資料還是在控制器中處理,同樣要做分離,不過這一步,同學們可以根據自己的意愿來,比如你可以添加倉庫層、服務層等,
這里就做簡單點,在app目錄下,創建Models檔案夾,繼續創建User.php檔案,
# User.php
namespace App\Models;
class User {
protected $emails = [];
protected $githubs = [];
public function getEmailByName(string $name)
{
$this->setEmails();
return array_key_exists($name, $this->emails) ? $this->emails[$name] : '';
}
public function getGithubByName($name)
{
$this->setGithubs();
return array_key_exists($name, $this->githubs) ? $this->githubs[$name] : '';
}
public function setEmails()
{
$this->emails = [
'SexyPhoenix' => '[email protected]'
];
}
public function setGithubs()
{
$this->githubs = [
'SexyPhoenix' => 'https://github.com/SexyPhoenix'
];
}
}
更新DashboardController.php,
# DashboardController.php
......
use App\Models\User #add
......
public function index(Request $request)
{
$name = $request->get('name', 'world');
$user = new User(); # add
$data = https://www.cnblogs.com/SexyPhoenix/p/['name' => $name,
'email' => $user->getEmailByName($name), # update
'github' => $user->getGithubByName($name),# update
];
return $this->render('dashboard.php', $data);
}
訪問頁面,正常顯示,
八、剝離核心代碼
框架的基本架構已經搭建完成,但此時的核心代碼都寫在了index.php里面,另寫專案的話,無法復用此架構,接下來剝離出核心代碼,
在phoenix專案下創建Core檔案夾,繼續創建Phoenix.php檔案,移入核心代碼并優化,
# Phoenix.php
namespace Core; #注意此命名空間需要注冊
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
class Phoenix {
public $request;
public $routeMap;
public function handle(Request $request)
{
$this->request = $request;
try {
//url map
$this->getRouteMap();
$this->setRequestRoute();
$controller = (new ControllerResolver())->getController($request);
$arguments = (new ArgumentResolver())->getArguments($request, $controller);
return call_user_func_array($controller, $arguments);
} catch(\Exception $e) {
return new Response('File Not Found', 404);
}
}
public function setRequestRoute()
{
$this->request->attributes->add($this->routeMap->match($this->request->getPathInfo()));
}
public function getRouteMap()
{
$this->routeMap = new UrlMatcher(
$this->getCollection(),
(new RequestContext())->fromRequest($this->request)
);
}
public function getCollection()
{
return (
new YamlFileLoader(
new FileLocator(array(getcwd()))
)
)->load('routes/web.yaml');
}
}
更新index.php代碼,
ini_set('display_errors', 1);
error_reporting(-1);
require_once __DIR__.'/vendor/autoload.php';
$kernel = new Core\Phoenix();
$response = $kernel->handle(
Symfony\Component\HttpFoundation\Request::createFromGlobals()
);
$response->send();
注冊Core命名空間,打開composer.json檔案,
# composer.json
"autoload": {
"psr-4": {
"App\\": "app/",
"Core\\": "core/"
}
}
composer dump-autoload # 更新命名空間
重繪頁面,顯示正常,
九、優化框架
在前面用到HttpKernel組件時,為什么介紹它是框架的內核呢?
因為HttpKernel里面有個很重要的概念,派遣事件,給注冊過的不同監聽器監聽,
是用Mediator模式設計的,這種模式帶來的好處,就是使框架的擴展性得到極大的提高,
在請求到回應之前設計了八種鉤子,方便后期擴展,詳情看下面的鏈接,
KernelEvents鉤子介紹
同時,也可以用另一種監聽事件的方式,通過一個event subscriber(事件訂閱器),向派遣器精確通報它要訂閱哪些事件,下面對路由優化時,會用到這,
EventDispatcher組件使用說明
HttpKernel組件的功能僅止于此嗎? 當然不,它里面有一個很重要的類“HttpKernel類”,將框架的核心Core/Phoenix.php的程式都實作了,
只要phoenix框架核心類Phoenix繼承HttpKernel,并呼叫它的構造方法就行了,
下面來改造Core/Phoenix.php代碼,
# Phoenix.php
namespace Core;
use Symfony\Component\HttpFoundation\RequestStack; # add
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\EventDispatcher\EventDispatcher; # add
use Symfony\Component\HttpKernel\HttpKernel; # add
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
class Phoenix extends HttpKernel{ # 繼承HttpKernel
public function __construct()
{
$matcher = new UrlMatcher($this->getCollection(), new RequestContext());
$requestStack = new RequestStack();
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new RouterListener($matcher, $requestStack)); # 訂閱路由
# HttpKernel的建構式,可以點下面的鏈接進去看看
parent::__construct(
$dispatcher,
new ControllerResolver(),
$requestStack,
new ArgumentResolver()
);
}
public function getCollection()
{
return (
new YamlFileLoader(
new FileLocator(array(getcwd()))
)
)->load('routes/web.yaml');
}
}
HttpKernel類
index.php的代碼不用變,HttpKernel類里面也有handle方法,建議同學們看看HttpKernel類的原始碼,
十、依賴注入(Dependency Injection)
Phoenix類繼承了HttpKernel,是整個架構的核心,在框架里面定義了“路由監聽”,但如果框架不僅僅要對路由進行監聽,還要對response階段進行監聽呢?是不是繼續修改Phoenix類呢?
這樣的設計對于框架來說,是絕對不友好的,那有沒有方法解決呢?
當然有,可以通過在外面注入物件,框架通過type檢測,自動引入相關物件,
首先下載Symfony的DependencyInjection組件,
composer require symfony/dependency-injection
在core檔案夾下創建container.php檔案
# container.php
namespace Core;
use Symfony\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
$app = new ContainerBuilder();
$app->register('context', 'Symfony\Component\Routing\RequestContext');
$app->register('matcher', 'Symfony\Component\Routing\Matcher\UrlMatcher')
->setArguments(array(getCollection(), new Reference('context')));
$app->register('request_stack', 'Symfony\Component\HttpFoundation\RequestStack');
$app->register('controller_resolver', 'Symfony\Component\HttpKernel\Controller\ControllerResolver');
$app->register('argument_resolver', 'Symfony\Component\HttpKernel\Controller\ArgumentResolver');
$app->register('listener.router', 'Symfony\Component\HttpKernel\EventListener\RouterListener') # 路由監聽
->setArguments(array(new Reference('matcher'), new Reference('request_stack')));
$app->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher')
->addMethodCall('addSubscriber', array(new Reference('listener.router')));
$app->register('phoenix', 'Core\Phoenix')
->setArguments(array(
new Reference('dispatcher'),
new Reference('controller_resolver'),
new Reference('request_stack'),
new Reference('argument_resolver'),
));
return $app;
function getCollection()
{
return (
new YamlFileLoader(
new FileLocator(array(getcwd()))
)
)->load('routes/web.yaml');
}
別名和物件一一對應,后面可以通過別名獲取物件,
去掉core/phoenix.php里面的代碼,
namespace Core;
use Symfony\Component\HttpKernel\HttpKernel;
class Phoenix extends HttpKernel{
// public function __construct()
// {
// $matcher = new UrlMatcher($this->getCollection(), new RequestContext());
// $requestStack = new RequestStack();
// $dispatcher = new EventDispatcher();
// $dispatcher->addSubscriber(new RouterListener($matcher, $requestStack));
// parent::__construct(
// $dispatcher,
// new ControllerResolver(),
// $requestStack,
// new ArgumentResolver()
// );
// }
// public function getCollection()
// {
// return (
// new YamlFileLoader(
// new FileLocator(array(getcwd()))
// )
// )->load('routes/web.yaml');
// }
}
更新index.php代碼,
ini_set('display_errors', 1);
error_reporting(-1);
require_once __DIR__.'/vendor/autoload.php';
$app = require_once __DIR__.'/core/container.php'; # add
$response = $app->get('phoenix') # 通過別名獲取
->handle(
Symfony\Component\HttpFoundation\Request::createFromGlobals()
);
$response->send();
訪問 http://dev.phoenix.goods/dashboard?name=SexyPhoenix, 顯示正常,
到這里,框架的整個基本設計就結束了,之后需要什么功能,就可以自己用composer安裝組件了,composer還是很好用的,
同學們如果有什么疑問的,歡迎在評論區一起交流,ヾ(●′?`●) ,
最后,附一份最終代碼 phoenix web 架構,
參考Symfony官網 - 創建你自己的框架
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/29192.html
標籤:架構設計
