上一篇博客中,我們搭建了一個最簡單的框架,從單一入口的public/index.php進入,解析出相應的Controller和Action,去執行,渲染出相應的頁面或者輸出相應的數據。
但是我們可以看到在public/index.php文件中,是一堆代碼,如果之後,我要添加權限/事件等等的機制是不是也要也在這裡,那不難想象,不就的將來,index.php就會變成一個巨大無比的php文件。我們當然不想看到這樣的情景,所以我們需要將這些內容抽象出來,保持入口文件的簡單明了。
那我們要將這些內容抽象到那裡去呢?有聰明的同學已經想到了,就是之前在composer.json中定義的位置,我們來看一下composer.json文件:
{
"name": "craryprimitiveman/simple-framework",
"description": "A simple php framework",
"license": "MIT",
"authors": [
{
"name": "harrysun",
"email": "sunguangjun@126.com"
}
],
"require": {},
"autoload": {
"psr-4": {
"sf\\": "src/",
"app\\": ""
}
},
"repositories": [
{"type": "composer", "url": "http://packagist.phpcomposer.com"},
{"packagist": false}
]
}
可以看到autoload裡的psr-4裡還有個sf\\,他的地址是src/,這就是我們要放抽象出的內容的地方。
有人會問,為什麼不直接使用app\\ 作為namespace呢?因為想到之後要將src下的內容做成一個composer包,遷移到vendor中。
下面就正式開始抽象了。
在src下創建兩個文件夾,一個是base,一個是web。base用來存放基礎的類,web用來存放與web相關的類。因為將來框架可能還要支持php腳本的執行,所以要將base和web分開,將來要加php腳本時,只需要建立一個console的文件夾就好了。
在兩個文件夾中分別建立Application.php文件。
先來看在base裡的Application.php
<?php
namespace sf\base;
use Exception;
/**
* Application is the base class for all application classes.
* @author Harry Sun <sunguangjun@126.com>
*/
abstract class Application
{
/**
* @var string the namespace that controller classes are located in.
* This namespace will be used to load controller classes by prepending it to the controller class name.
* The default namespace is `app\controllers`.
*/
public $controllerNamespace = 'app\\controllers';
/**
* Runs the application.
* This is the main entrance of an application.
*/
public function run()
{
try {
return $this->handleRequest();
} catch (Exception $e) {
return $e;
}
}
/**
* Handles the specified request.
*/
abstract public function handleRequest();
}
它是一個抽象類,實現了一個簡單的run方法,run方法就是去執行以下handleRequest方法。
它定義了一個抽象方法handleRequest,等待被繼承,實現。
它定義了一個controllerNamespace屬性,記錄controller存放的namesapce,默認值是'app\\controllers'。
再來看在web裡的Application.php
<?php
namespace sf\web;
/**
* Application is the base class for all application classes.
* @author Harry Sun <sunguangjun@126.com>
*/
class Application extends \sf\base\Application
{
/**
* Handles the specified request.
* @return Response the resulting response
*/
public function handleRequest()
{
$router = $_GET['r'];
list($controllerName, $actionName) = explode('/', $router);
$ucController = ucfirst($controllerName);
$controllerName = $this->controllerNamespace . '\\' . $ucController . 'Controller';
$controller = new $controllerName();
return call_user_func([$controller, 'action'. ucfirst($actionName)]);
}
}
是不是覺得很眼熟,其實就是將之前放在index.php中的內容放到Application的handleRequest方法裡了。
然後我們需要從入口文件調用到這裡的代碼,這就很簡單了,index.php的內容如下:
<?php require_once(__DIR__ . '/../vendor/autoload.php'); $application = new sf\web\Application(); $application->run();
直接去new一個web Application的實例,執行run方法就可以了,是不是很簡單。
訪問一下:http://localhost/simple-framework/public/index.php?r=site/test,你可以看到上一次一樣的結果。
好了,今天就先到這裡。項目內容和博客內容也都會放到Github上,歡迎大家提建議。
code:https://github.com/CraryPrimitiveMan/simple-framework/tree/0.2
blog project:https://github.com/CraryPrimitiveMan/create-your-own-php-framework