建立一個空的 composer.json 文件。 { } 或者在空目錄下執行: composer init 則能夠生成一個類型以下的文件: { "name": "charlie/my_first_framework", "description": "My First Framework", "type": "project", "license": "MIT", "authors": [ { "name": "Charlie", "email": "demo@qq.com" } ], "minimum-stability": "dev", "require": {} }
咱們接下來安裝一個管理路由的包: noahbuscher/macaw。 功能比這個更增強大的路由包有不少,可是爲了簡單起見,咱們選擇安裝這個包。
當前目錄結構爲: ➜ demo tree . ├── composer.json ├── composer.lock └── vendor ├── autoload.php ├── composer │ ├── ClassLoader.php │ ├── LICENSE │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_real.php │ ├── autoload_static.php │ └── installed.json └── noahbuscher └── macaw ├── LICENSE.md ├── Macaw.php ├── README.md ├── composer.json ├── composer.lock └── config ├── Web.config └── nginx.conf
public/index.phpphp
咱們在根目錄下新建一個public文件夾,並在該文件夾下新建 index.php。index.php 文件相似於一個大廈的入口,咱們全部的請求都運行 index.php。 下面是 index.php 文件的代碼: // 自動加載vendor目錄下的包require '../vendor/autoload.php'; routes.php 此時咱們觀察 index.php,除了把vendor下面的包都 require 進來了外,其餘啥都沒幹。那麼如何響應各類各樣的請求呢? 咱們須要定義路由。路由就有點像快遞分揀站,把寫着不一樣地址的請求分撥給不一樣的控制器處理。 那麼咱們在根目錄下建立一個 routes 文件夾,並在該文件夾下建立 web.php 文件。
<?php use NoahBuscher\Macaw\Macaw; Macaw::get('hello', function () { echo "hello world"; }); Macaw::dispatch();
> cd public > php -S localhost:8001
上面咱們僅僅實現了訪問一個地址,返回一個字符串。html
無論怎麼樣,咱們先新建三個文件夾再說,即 views、models、controllers。mysql
新建 controllersHomeController.php 文件,代碼以下:nginx
<?php namespace App\Controllers; use App\Models\Article; class HomeController extends BaseController{ public function home() { echo "<h1>This is Home Page</h1>"; } }
Macaw::get('', 'App\\Controllers\\HomeController@home'); 總體代碼爲: <?php use NoahBuscher\Macaw\Macaw; Macaw::get('hello', function () { echo "hello world"; }); Macaw::get('', 'App\\Controllers\\HomeController@home'); Macaw::dispatch();
修改 composer.json 中添加:git
"autoload": { "classmap": [ "app/controllers", "app/models" ] }
咱們順便把models也加載進來。web
composer dump-autoloadsql
刷新自動加載
Model鏈接數據庫
咱們建立一個Article Model,這個 Model 對應數據庫一張表。此時咱們先用mysql 命令行工具新建一個 demo_database 的數據庫,裏面有一張表 articles , 表的結構大體以下:數據庫
mysql> desc articles;json
+---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(256) | YES | | NULL | | | content | varchar(256) | YES | | NULL | | +---------+--------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)
咱們再在表裏面填入數據:瀏覽器
mysql> select * from articles;
+----+--------+--------------+| id | title | content | +----+--------+--------------+ | 1 | hhhhh | heheheheheh || 2 | hhhhh2 | heheheheh2eh | +----+--------+--------------+ 2 rows in set (0.00 sec)
固然了,咱們如今是直接經過 MySQL 的 insert 命令直接填入數據,後續咱們能夠經過咱們的框架新建 model 。
接下來咱們要作的就是怎麼在 Model 中鏈接數據庫取到數據庫裏面的數據啦! 本文使用的 php 7.1,咱們使用 mysqli 來鏈接數據庫查詢數據:
<?php namespace App\Models; class Article { public static function first() { //mysql_connect is deprecated $mysqli = new \mysqli('localhost', 'root', 'w.x.c.123', 'demo_database'); if ($mysqli->connect_errno) { echo "Failed to connect to Mysql: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error(); } $mysqli->set_charset('utf-8'); $result = $mysqli->query("SELECT * FROM articles limit 0,1"); $article = $result->fetch_array(); if ($article) { echo "<p>" . $article['title'] . "</p>"; echo "<p>" . $article['content'] . "</p>"; } $mysqli->close(); } }
這麼一來咱們就能夠在控制器裏面使用
Article::first();
來查詢 articles 表裏面的第一條article數據,而後咱們再經過 echo 返回給瀏覽器。
<?php namespace App\Controllers; use App\Models\Article; class HomeController extends BaseController{ public function home() { Article::first(); } }
View層
看上面的代碼,咱們在 Article Model 中連續寫了兩條 echo 語句來格式化輸出。若是後續咱們的頁面十分複雜的時候,咱們把全部的格式化輸出的代碼都寫在 Model 裏面感受是個災難。咱們應該把這些格式化輸出的代碼分離出來,這即是咱們說的 MVC 層的 View 層。
咱們在 views 目錄下新建 home.php:
<?php echo "<p>" . $article['title'] . "</p>";echo "<p>" . $article['content'] . "</p>";
咱們再改寫一下 Article.php,刪除echo 那兩行,直接
return article;
而後咱們在 HomeController 中指定要使用的 view:
<?php namespace App\Controllers; use App\Models\Article; class HomeController extends BaseController{ public function home() { $article = Article::first(); require dirname(__FILE__) . "/../views/home.php"; } }
咱們這裏的 view 層僅僅是用 PHP 拼接了 html,後續咱們須要實現更加複雜的視圖的時候,咱們能夠引入模版引擎。
ORM
咱們一路從一個空文件夾開始,打造一個本身的一個框架,感受並無寫多少代碼,惟一寫了好幾行代碼感受比較麻煩的就是鏈接數據庫來查詢數據了。咱們咱們有不少 Model,要實現 增刪改查的話,咱們豈不是要重複 鏈接,查詢、插入、刪除、更新,而後關閉鏈接?咱們應該把這些功能分裝一下。
怎麼封裝?有其餘人寫好的包了,直接拿來用吧~ 固然若是你想本身造輪子的話,也能夠本身實現一下。
咱們這裏使用 illuminate/database:
composer require illuminate/database
而後咱們在 public/index.php 中引入:
use Illuminate\Database\Capsule\Manager as Capsule;
require '../vendor/autoload.php';
// Eloquent ORM
$capsule = new Capsule();
$capsule->addConnection(require '../config/database.php');
$capsule->bootEloquent();
//路由配置require '../routes/web.php';
咱們在鏈接數據的時候,使用了 config/database.php 的數據庫配置文件。
<?php return [ 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'demo_database', 'username' => 'root', 'password' => 'secret', 'charset' => 'utf8', 'collation' => 'utf8_general_ci', 'prefix' => '' ];
接下來咱們就能夠刪掉 models/Article.php 文件中咱們寫的大部分代碼,而僅僅須要繼承IlluminateDatabaseEloquentModel 來使用 Eloquent ORM 的功能:
<?php/** * Created by PhpStorm. * User: W * Date: 24/03/2018 * Time: 22:23 */ namespace App\Models; use Illuminate\Database\Eloquent\Model; class Article extends Model{ public $timestamps = false; }
更多Eloquent ORM的功能,您也能夠本身查閱文檔。
總結
好了,咱們一個 MVC 框架基本上就搭建完了,咱們回頭看一下整個框架目錄結構,是否是跟 Laravel 有點像呢?
➜ myFirstFramework git:(master) ✗ tree
. ├── README.md ├── app │ ├── controllers │ │ ├── BaseController.php │ │ └── HomeController.php │ ├── models │ │ └── Article.php │ └── views │ └── home.php ├── composer.json ├── composer.lock ├── config │ └── database.php ├── public │ └── index.php ├── routes │ └── web.php └── vendor ...