#1.此框架架構模式遵循的是mvc思想
- M:model模型
- V:view視圖
- C:controller控制器
#2.mvc目錄結構創建
- 創建項目目錄php_mvc
```cpp
|-core 框架核心目錄
| |-App.class.php URL重寫類
| |-Controller.class.php 所有控制器的基類
| |-MyException.class.php 用戶自定義的錯誤異常類
| |-Model.class.php 數據庫操作類 業務邏輯層
|-config 配置
| |-constants.php 項目常量文件
|-app 前臺
| |-public 前臺公共文件(js、css)
| |-controllers 存放所有的控制器目錄
| |-Home.class.php
| |-Test.class.php
| |-models 存放所有的model類
| |-views 存放所有的頁面
| | |-index index目錄
| | | |-index.php 前臺首頁頁面
| | |-error 錯誤目錄
| | | |-error.php 錯誤頁面
|-web 后臺
| |-public 后臺公共文件(js、css)
| |-controllers 存放所有的控制器目錄
| |-Home.class.php 后臺首頁控制器
| |-models 存放所有的model類
| |-views 存放所有的頁面
| |-index.php 項目后臺入口文件,單一入口
| |-.htaccess 后臺分布式配置文件
|-index.php 項目前臺入口文件,單一入口
|-.htaccess 分布式配置文件
```
#3.單一入口
一般來說,在大部分項目中都是采用單一入口的方式,符合php的規范。
所謂單一入口就是在整個項目運行的過程中,需要加載的類和方法或者模板都是通過index.php來加載的。
這樣做的主要原因是為了安全。此外單一入口不代表只有一個入口,最外層的index.php是我們前臺的入口文件。web目錄下的index.php是我們后臺的入口文件。
#4.URL路由之pathinfo路由
我們常見pathinfo地址如下:
```cpp
localhost/php_mvc/index.php?controller=home&method=index
```
這個路由地址,是運行前臺的index.php入口,并且傳遞了兩個參數controller和method
controller表示執行哪個控制器,method表示執行哪個方法。上面這條url就是要執行home控制器的index方法。
我們現在就要實現在前臺index.php接受這兩個參數,當沒有這兩個參數時,默認執行home控制器中的index方法。然后引入相應的類,加載指定控制器中的指定方法,實例化控制器類,調用控制器中的方法。
```cpp
|-index.php 項目前臺入口文件,單一入口
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/24
* Time: 下午5:15
*/
echo "<meta charset='utf-8'>";
require_once 'app/controllers/Home.class.php';
require_once 'app/controllers/Test.class.php';
//接受兩個參數 controller控制器名稱 method控制器中的方法
$controller = isset($_GET['controller']) ? $_GET['controller'] : 'home';
$method = isset($_GET['method']) ? $_GET['method'] : 'index';
//加載指定控制器中的制定方法
//實例化控制器類
$c = new $controller;
//調用控制器中的方法
$c->$method();
```
```cpp
|-app 前臺
| |-controllers 存放所有的控制器目錄
| |-Home.class.php
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/24
* Time: 下午5:44
*/
class Home
{
public function index(){
echo "這里是home控制器里的index方";
}
}
```
```cpp
|-app 前臺
| |-controllers 存放所有的控制器目錄
| |-Test.class.php
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/24
* Time: 下午5:44
*/
class Test
{
public function index(){
echo "這里是test控制器的index方法";
}
}
```
下面的前兩個url在瀏覽器中應該是一樣的結果
```cpp
localhost/php_mvc/index.php
localhost/php_mvc/index.php?controller=home&method=index
localhost/php_mvc/index.php?controller=test&method=index
```
#5.隱藏index.php
我們開始對url進行重寫,首先為了先把index.php給隱藏,創建分布式配置文件
```cpp
|-.htaccess 分布式配置文件
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FIELNAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
```
然后在你的httpd.conf文件中把下列配置項開啟,也就是前面的#號刪掉
```cpp
#LoadModule rewrite_module modules/mod_rewrite.so
```
這樣我們就把url進行了重寫,我們可以進行測試,修改文件
```cpp
|-index.php 項目前臺入口文件,單一入口
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/24
* Time: 下午5:15
*/
echo $_GET['url'];
```
然后在瀏覽器中輸入
```cpp
http://localhost/php_mvc/test/index/id/13
```
如果這時在瀏覽器中顯示如下,則表示成功
```cpp
test/index/id/13
```
也就是把index.php后面的內容全部都輸出出來了。
#6.URL路由之重寫URL路由
剛才已經成功獲取到了url,然后我們要對url進行解析,我們建立一個新的類文件來處理,這個類文件要實現的功能是:得到控制器的名稱、得到方法名、其他參數并保存。組裝得到控制器的路徑,判斷控制器文件是否存在,存在則實例化,然后判斷方式是否存在,存在則執行方法,如果控制器文件或者方法不存在則執行相應地異常報錯。
```cpp
|-core
| |-App.class.php URL重寫類
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/25
* Time: 上午10:53
*/
class App
{
protected static $controller = 'Home';//控制器名
protected static $method = 'index';//方法名
protected static $pams = array();//其他參數
/**
* url重寫路由的url地址解析方法
*/
protected static function paseUrl(){
if(isset($_GET['url'])){
$url = explode('/',$_GET['url']);
//得到控制器
if(isset($url[0])){
self::$controller = $url[0];
unset($url[0]);
}
//得到方法名
if(isset($url[1])){
self::$method = $url[1];
unset($url[1]);
}
//判斷是否有其他參數
if(isset($url)){
self::$pams = array_values($url);
}
}
}
/**
* 項目的入口方法
* @throws Exception
*/
public static function run(){
self::paseUrl();
//得到控制器的路徑
$url = 'app/controllers/'.self::$controller.'.class.php';
//判斷控制器文件是否存在
if(file_exists($url)){
$c = new self::$controller;
}else{
throw new Exception('控制器不存在');
}
//執行方法
if(method_exists($c,self::$method)){
$m = self::$method;
$c->$m();
}else{
throw new Exception('方法不存在');
}
}
}
```
在入口文件這里,我們要在執行run方法,并捕獲異常情況,如有異常則輸出
```cpp
|-index.php 項目前臺入口文件,單一入口
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/24
* Time: 下午5:15
*/
echo "<meta charset='utf-8'>";
require_once 'core/App.class.php';
require_once 'app/controllers/Test.class.php';
require_once 'app/controllers/Home.class.php';
try{
App::run();
throw new Exception();
}catch(Exception $e){
echo $e->getMessage();
}
```
此時我們在瀏覽器中輸入
```cpp
http://localhost/php_mvc/home/index/id/13
```
那么在瀏覽器中展示如下,表示成功
```cpp
這里是home控制器里的index方法
```
如果我們在瀏覽器中輸入一個不存在的控制器,比如
```cpp
http://localhost/php_mvc/article/index/id/13
```
那么在瀏覽器將中展示出異常信息
```cpp
控制器不存在
```
#7.自動加載類文件
在一個正常的項目中,會用到很多的類文件,我們就要寫很多航require的語句,這樣會讓代碼的冗余度加大,所以為了處理這個情況,php中有一個方法是自動加載類函數,自動加載方法。所以我們需要一個方法去實現加載指定的類文件。具體目標有
- 明確指明改項目中所有類存放目錄地址,這里就是控制器controllers,模型model,核心core這三個地方
- 判斷類文件在哪個目錄中,在找到后require過來,如果都不存在那么異常報錯
- 為什么不用__autoload方法來加載類文件,如果項目中前后臺都有autoload方法,可能會產生重定義錯誤。所以我們直接自己定義自動加載類的方法,然后在入口文件處通過spl_autoload_register將我們的類文件進行加載。
```cpp
|-core 框架核心目錄
| |-App.class.php URL重寫類
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/25
* Time: 上午10:53
*/
class App
{
/**
* 自動加載類方法
* @param $className
* @throws Exception
*/
public static function myAutoloader($className){
//控制器類文件目錄
$controller = 'app/controllers/'.$className.'.class.php';
//模型類文件目錄
$model = 'app/models/'.$className.'.class.php';
//核心類文件目錄
$core = 'core/'.$className.'.class.php';
if(file_exists($controller)){
require_once $controller;
}else if(file_exists($model)){
require_once $model;
}else if(file_exists($core)){
require_once $core;
}else{
throw new Exception('類文件不存在');
}
}
}
```
```cpp
|-index.php 項目前臺入口文件,單一入口
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/24
* Time: 下午5:15
*/
echo "<meta charset='utf-8'>";
require_once 'core/App.class.php';
//注冊一個
spl_autoload_register(array('App','myAutoloader'));
try{
App::run();
throw new Exception();
}catch(Exception $e){
echo $e->getMessage();
}
```
此時我們在瀏覽器中輸入
```cpp
http://localhost/php_mvc/home/index
```
如果展示如下,則表示自動加載類已經成功
```cpp
這里是home控制器里的index方法
```
特別注意,創建類的時候,類的名稱和文件的名稱要是一致的。
#8.解析URL參數
在剛才的app.class.php類parseurl方法中,我們已經獲取到了url的參數,我們繼續在run方法中對這個參數進行判斷,是否存在多余的參數,如果有參數,那么我們要傳遞參數,否則就不傳遞參數。
對于要傳遞的參數,我們要判斷有幾個參數,鍵值是否合法。
是否大于0,是否是偶數,for循環,不滿足的都報錯“非法參數”
```cpp
|-core 框架核心目錄
| |-App.class.php URL重寫類
/**
* 項目的入口方法
* @throws Exception
*/
public static function run(){
self::paseUrl();
//得到控制器的路徑
$url = 'app/controllers/'.self::$controller.'.class.php';
//判斷控制器文件是否存在
if(file_exists($url)){
$c = new self::$controller;
}else{
throw new Exception('控制器不存在');
}
//執行方法
if(method_exists($c,self::$method)){
$m = self::$method;
$new_pams = array();
$num = count(self::$pams);
//傳遞參數,判斷是否有參數
if($num > 0){
//判斷傳遞的參數的數量是否是2的倍數
if($num % 2 == 0){
//將參數進行處理
for($i=0;$i<$num;$i+=2){
$new_pams[self::$pams[$i]] = self::$pams[$i+1];
}
}else{
throw new Exception('非法參數!');
}
}
$c->$m($new_pams);
}else{
throw new Exception('方法不存在');
}
}
```
```cpp
|-app 前臺
| |-controllers 存放所有的控制器目錄
| |-Home.class.php
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/24
* Time: 下午5:44
*/
class Home
{
public function index($data = array()){
echo "這里是home控制器里的index方法";
echo "<pre>";
print_r($data);
}
}
```
此時我們就已經將多余的參數都傳遞到指定的控制器的方法中了。在瀏覽器中輸入
```cpp
http://localhost/php_mvc/home/index/cityname/shanghai/id/7
```
如果瀏覽器中顯示如下,則表示成功
```cpp
這里是home控制器里的index方法
Array
(
[cityname] => shanghai
[id] => 7
)
```
#9.創建控制器基類
控制器基類要實現的功能就是,實現加載相應的頁面的方法并且傳遞數據到頁面中。
為什么要創建控制器基類呢,在mvc中,工作原理是,網站首頁->Home控制器->index方法->查詢需要的所有數據->將數據發送到(view層)->展示給用戶
我們新建一個controller基類,實現加載相應頁面的方法,首先判斷頁面是否存在,如果存在那么則引入。并且傳遞數據到相應的頁面中。
```cpp
|-core 框架核心目錄
| |-Controller.class.php 所有控制器的基類
<?php
/**
* 所有控制器的基類
* User: find35.com
* Date: 15/12/26
* Time: 上午9:53
*/
class Controller
{
/**
* 加載指定的模板頁面
* @param $page
* @param array $data
*/
public function show($page,$data=array()){
$url = "app/views/".$page.".php";
//判斷頁面是否存在
if(file_exists($url)){
require_once $url;
}
}
}
```
之后讓所有其他的類,繼承此基類。調用show方法來加載view層。
```cpp
|-app 前臺
| |-controllers 存放所有的控制器目錄
| |-Home.class.php
<?php
/**
* 前臺首頁控制器
* User: find35.com
* Date: 15/12/24
* Time: 下午5:44
*/
class Home extends Controller
{
public function index($data = array()){
//加載首頁頁面
$this->show('index/index',$data);
}
}
```
我們新建一個view層的模板文件,在隨便里面寫點東西
```cpp
|-app 前臺
| |-views 存放所有的頁面
| | | |-index.php 前臺首頁頁面
<?php
/**
* 前臺首頁頁面
* User: find35.com
* Date: 15/12/26
* Time: 下午1:09
*/
echo "前臺首頁";
echo '<pre>';
print_r($data);
echo '</pre>';
```
此時在瀏覽器中輸入
```cpp
http://localhost/php_mvc/home/index/cityname/shanghai/id/7
```
顯示如下,則表示成功
```cpp
前臺首頁Array
(
[cityname] => shanghai
[id] => 7
)
```
#10.mvc工作流
mvc中是通過控制器,調用里面具體的方法,來實現我們要加載哪些的模板。這些都是在控制器里進行的,并且我們可以對數據庫進行操作。
#11.錯誤處理
在項目中,當報錯時,會加載相應的錯誤頁面。當我們throw一個異常的時候,將自定義的錯誤頁面進行加載。
首頁創建一個自定義的錯誤異常的模板
```cpp
|-app 前臺
| |-views 存放所有的頁面
| | |-error 錯誤目錄
| | | |-error.php 錯誤頁面
<?php
/**
* 錯誤頁面
* User: find35.com
* Date: 15/12/26
* Time: 下午7:46
*/
echo "<h2>這里是自定義的異常報錯模板:".$msg."<h2>";
```
然后我們開始創建一個自定義的錯誤類
```cpp
|-core 框架核心目錄
| |-MyException.class.php 用戶自定義的錯誤異常類
<?php
/**
* 用戶自定義的錯誤異常類
* User: find35.com
* Date: 15/12/26
* Time: 下午7:48
*/
class MyException extends Exception
{
/**
* 錯誤頁面加載
* @param $msg
*/
public function showError($msg){
$err_dir = 'app/views/error/error.php';
//判斷錯誤頁面是否存在
if(file_exists($err_dir)){
require $err_dir;
}
}
}
```
然后我們開始在項目中使用它,首先在app類中使用
```cpp
|-core 框架核心目錄
| |-App.class.php URL重寫類
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/25
* Time: 上午10:53
*/
class App
{
protected static $controller = 'Home';//控制器名
protected static $method = 'index';//方法名
protected static $pams = array();//其他參數
/**
* url重寫路由的url地址解析方法
*/
protected static function paseUrl(){
if(!empty($_GET['url'])){
$url = explode('/',$_GET['url']);
//得到控制器
if(isset($url[0])){
self::$controller = $url[0];
unset($url[0]);
}
//得到方法名
if(isset($url[1])){
self::$method = $url[1];
unset($url[1]);
}
//判斷是否有其他參數
if(isset($url)){
self::$pams = array_values($url);
}
}
}
/**
* 項目的入口方法
* @throws Exception
*/
public static function run(){
self::paseUrl();
//得到控制器的路徑
$url = 'app/controllers/'.self::$controller.'.class.php';
//判斷控制器文件是否存在
if(file_exists($url)){
$c = new self::$controller;
}else{
throw new MyException('控制器不存在');
}
//執行方法
if(method_exists($c,self::$method)){
$m = self::$method;
$new_pams = array();
$num = count(self::$pams);
//傳遞參數,判斷是否有參數
if($num > 0){
//判斷傳遞的參數的數量是否是2的倍數
if($num % 2 == 0){
//將參數進行處理
for($i=0;$i<$num;$i+=2){
$new_pams[self::$pams[$i]] = self::$pams[$i+1];
}
}else{
throw new MyException('非法參數!');
}
}
$c->$m($new_pams);
}else{
throw new MyException('方法不存在');
}
}
/**
* 自動加載類方法
* @param $className
* @throws Exception
*/
public static function myAutoloader($className){
//控制器類文件目錄
$controller = 'app/controllers/'.$className.'.class.php';
//模型類文件目錄
$model = 'app/models/'.$className.'.class.php';
//核心類文件目錄
$core = 'core/'.$className.'.class.php';
if(file_exists($controller)){
require_once $controller;
}else if(file_exists($model)){
require_once $model;
}else if(file_exists($core)){
require_once $core;
}else{
throw new MyException('類文件不存在');
}
}
}
```
最后我們在入口文件中也是用它
```cpp
|-index.php 項目前臺入口文件,單一入口
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/24
* Time: 下午5:15
*/
echo "<meta charset='utf-8'>";
require_once 'core/App.class.php';
//注冊一個
spl_autoload_register(array('App','myAutoloader'));
try{
App::run();
throw new MyException();
}catch(MyException $e){
$e->showError(($e->getMessage()));
}
```
此時我們在瀏覽器中輸入
```cpp
http://localhost/php_mvc//home2/index
```
如果返回的如下,則表示成功
```cpp
這里是自定義的異常報錯模板:控制器不存在
```
#12.項目后臺mvc架構
其實后臺和前臺差不多,在web下也有一個index.php文件,然后也需要隱藏index.php,所以我們直接將.htaccess也拿過來。
```cpp
|-web 后臺
| |-.htaccess 后臺分布式配置文件
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FIELNAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
```
然后后臺入口文件和前臺的入口文件內容也差不多,只是引入文件的路徑需要調整。還有就是我們要區分前后臺,根據前后臺定義的變量APP來判斷。前臺入口文件也需要定義 define('APP','app');
```cpp
|-web 后臺
| |-index.php 項目后臺入口文件,單一入口
<?php
/**
* 項目后臺入口文件
* User: find35.com
* Date: 15/12/27
* Time: 下午3:12
*/
echo "<meta charset='utf-8'>";
require_once '../core/App.class.php';
//注冊一個
define('APP','web');
spl_autoload_register(array('App','myAutoloader'));
try{
App::run();
}catch(MyException $e){
$e->showError(($e->getMessage()));
}
```
然后我們也需要根據入口文件傳遞的APP來調整app.class.php文件里面的路徑。
```cpp
|-core 框架核心目錄
| |-App.class.php URL重寫類
<?php
/**
* Created by PhpStorm.
* User: find35.com
* Date: 15/12/25
* Time: 上午10:53
*/
class App
{
protected static $controller = 'Home';//控制器名
protected static $method = 'index';//方法名
protected static $pams = array();//其他參數
/**
* url重寫路由的url地址解析方法
*/
protected static function paseUrl(){
if(!empty($_GET['url'])){
$url = explode('/',$_GET['url']);
//得到控制器
if(isset($url[0])){
self::$controller = $url[0];
unset($url[0]);
}
//得到方法名
if(isset($url[1])){
self::$method = $url[1];
unset($url[1]);
}
//判斷是否有其他參數
if(isset($url)){
self::$pams = array_values($url);
}
}
}
/**
* 項目的入口方法
* @throws Exception
*/
public static function run(){
self::paseUrl();
//判斷是前臺還是后臺
if(APP == 'app'){
//得到控制器的路徑
$url = 'app/controllers/'.self::$controller.'.class.php';
}
if(APP == 'web'){
//得到控制器的路徑
$url = 'controllers/'.self::$controller.'.class.php';
}
//判斷控制器文件是否存在
if(file_exists($url)){
$c = new self::$controller;
}else{
throw new MyException('控制器不存在');
}
//執行方法
if(method_exists($c,self::$method)){
$m = self::$method;
$new_pams = array();
$num = count(self::$pams);
//傳遞參數,判斷是否有參數
if($num > 0){
//判斷傳遞的參數的數量是否是2的倍數
if($num % 2 == 0){
//將參數進行處理
for($i=0;$i<$num;$i+=2){
$new_pams[self::$pams[$i]] = self::$pams[$i+1];
}
}else{
throw new MyException('非法參數!');
}
}
$c->$m($new_pams);
}else{
throw new MyException('方法不存在');
}
}
/**
* 自動加載類方法
* @param $className
* @throws Exception
*/
public static function myAutoloader($className){
if(APP == 'app'){
//控制器類文件目錄
$controller = 'app/controllers/'.$className.'.class.php';
//模型類文件目錄
$model = 'app/models/'.$className.'.class.php';
//核心類文件目錄
$core = 'core/'.$className.'.class.php';
}
if(APP == 'web'){
//控制器類文件目錄
$controller = 'controllers/'.$className.'.class.php';
//模型類文件目錄
$model = 'models/'.$className.'.class.php';
//核心類文件目錄
$core = '../core/'.$className.'.class.php';
}
if(file_exists($controller)){
require_once $controller;
}else if(file_exists($model)){
require_once $model;
}else if(file_exists($core)){
require_once $core;
}else{
throw new MyException('類文件不存在');
}
}
}
```
然后我們也建立一個后臺首頁控制器
```cpp
|-web 后臺
| |-controllers 存放所有的控制器目錄
| |-Home.class.php 后臺首頁控制器
<?php
/**
* 網站后臺首頁
* User: find35.com
* Date: 15/12/27
* Time: 下午3:19
*/
class Home
{
public function index(){
echo '這里是后臺的控制器首頁';
}
}
```
此時我們在瀏覽器中輸入
```cpp
http://localhost/php_mvc/web/
```
如果顯示如下則表示成功
```cpp
這里是后臺的控制器首頁
```
#13.封裝一個單例模式的MODEL類
單例模式就是一個類在使用的時候只能有一個實例,類的實例是在類內部進行創建,好處是大大的節省了資源的開銷,方便訪問類的實例,使用最多的地方是數據庫類的封裝。具體實現的方法是將我們的構造方法進行private進行修飾,禁止在類外進行實例化,因此只要你在類面進行實例化,就會報錯。再類里面定義一個,可以在類里面得到一個實例的方法。判斷類是否存在,如果存在則返回否則創建。
我們創建一個model.class.php數據庫操作類
```cpp
|-core 框架核心目錄
| |-Model.class.php 數據庫操作類 業務邏輯層
<?php
/**
* 數據庫操作類
* User: find35.com
* Date: 15/12/27
* Time: 下午4:52
*/
class Model
{
protected static $_instance;
//單例模式 不允許在類外對類進行實例化
private function __construct(){}
//獲得類的實例
public static function getSingleton(){
//判斷我們類的實例是否存在,沒有則創建之
if(!isset(self::$_instance)){
self::$_instance = new self();
}
return self::$_instance;
}
}
```
再類中對構造函數給予了private權限,因此無法在外面對這個類進行實例化,然后我們在入口文件這里執行以下這個方法,看看有沒有東西
```cpp
|-index.php 項目前臺入口文件,單一入口
<?php
/**
* 項目前臺入口文件
* User: find35.com
* Date: 15/12/24
* Time: 下午5:15
*/
echo "<meta charset='utf-8'>";
require_once 'core/App.class.php';
//注冊一個
define('APP','app');
spl_autoload_register(array('App','myAutoloader'));
try{
App::run();
}catch(MyException $e){
$e->showError($e->getMessage());
}
$db = Model::getStringleton();
print_r($db);
```
此時我們在瀏覽器中輸入
```cpp
http://localhost/php_mvc/
```
如果返回如下,則表示成功
```cpp
前臺首頁Model Object ( )
```
#14.PDO方式連接MySQL數據庫
采用的是PDO的方式進行封裝,PDO是PHP中的一個擴展庫,他是一個純面向對象的,好處就是提供了一個可以連接各種數據庫的接口,另外PDO中的prepare預處理的方式可以大大減少sql語句的注入機器相關的安全性。
和其他框架一樣,我們將關于數據庫信息寫入一個配置文件中。
```cpp
|-config 配置
| |-constants.php 項目常量文件
<?php
/**
* 項目常量文件
* User: find35.com
* Date: 15/12/30
* Time: 下午8:49
*/
define('HOST','localhost');//服務器地址
define('UNAME','root');//數據庫賬號
define('UPASS','');//數據庫密碼
define('DBNAME','test');//操作的數據庫名
```
之后我們在前臺入口文件引入這個文件。然后我們在model.class.php類中封裝一個方法來連接數據庫。
```cpp
|-core 框架核心目錄
| |-Model.class.php 數據庫操作類 業務邏輯層
<?php
/**
* 數據庫操作類
* User: find35.com
* Date: 15/12/27
* Time: 下午4:52
*/
class Model
{
protected static $_instance;
protected static $_link;
/**
* 單例模式 不允許在類外對類進行實例化
*/
private function __construct(){}
/**
* 獲得類的實例
* @return mixed|Model
*/
public static function getStringleton(){
//判斷我們類的實例是否存在,沒有則創建之
if(!isset(self::$_instance)){
self::$_instance = new self();
}
//連接數據庫
self::connect(HOST,UNAME,UPASS,DBNAME);
return self::$_instance;
}
/**
* 連接數據庫方法
* @param $host 服務器地址
* @param $username 數據庫賬號
* @param $userpass 數據庫密碼
* @param $dbname 操作的數據庫名
*/
protected static function connect($host,$username,$userpass,$dbname){
try{
self::$_link = new PDO("mysql:host={$host};dbname={$dbname}",$username,$userpass);
if(self::$_link){
echo '連接數據庫成功';
}
}catch (PDOException $e){
MyException::showError($e->getMessage());
}
}
}
```
我們把自定義的異常報錯類的showerror方法設置為static屬性,此處不貼代碼了
然后我們在入口文件調用下,看看是否可以
```cpp
|-index.php 項目前臺入口文件,單一入口
<?php
/**
* 項目前臺入口文件
* User: find35.com
* Date: 15/12/24
* Time: 下午5:15
*/
echo "<meta charset='utf-8'>";
require_once 'core/App.class.php';
require_once 'config/constants.php';
//注冊一個
define('APP','app');
spl_autoload_register(array('App','myAutoloader'));
try{
App::run();
}catch(MyException $e){
$e->showError($e->getMessage());
}
$db = Model::getStringleton();
```
瀏覽器中輸入
```cpp
http://localhost/php_mvc
```
返回如下,則表示成功
```cpp
前臺首頁連接數據庫成功
```
#15.MODEL層CURD的實現
首先我們在test庫中先建立數據庫表users
```cpp
CREATE TABLE users (
`id` INT(10) AUTO_INCREMENT ,
`username` VARCHAR(255) ,
`userpass` VARCHAR(255) ,
`create_time` INT(10),PRIMARY KEY (id));
INSERT INTO users (username,userpass,create_time) VALUES
('zhang','e10adc3949ba59abbe56e057f20f883e',1451515405),
('zhang2','e10adc3949ba59abbe56e057f20f883e',1451515406),
('zhang3','e10adc3949ba59abbe56e057f20f883e',1451515407),
('zhang4','e10adc3949ba59abbe56e057f20f883e',1451515408),
('zhang5','e10adc3949ba59abbe56e057f20f883e',1451515409);
```
這里是使用預處理語言來查詢數據庫,注意設置數據返回類型,數據如何進行報錯。MODEL的CURD來了。
```cpp
|-core 框架核心目錄
| |-Model.class.php 數據庫操作類 業務邏輯層
<?php
/**
* 數據庫操作類
* User: find35.com
* Date: 15/12/27
* Time: 下午4:52
*/
class Model
{
protected static $_instance;
protected static $_link;
protected $whereStr = '';//用來存儲where條件
/**
* 單例模式 不允許在類外對類進行實例化
*/
private function __construct(){}
/**
* 獲得類的實例
* @return mixed|Model
*/
public static function getStringleton(){
//判斷我們類的實例是否存在,沒有則創建之
if(!isset(self::$_instance)){
self::$_instance = new self();
}
//連接數據庫
self::connect(HOST,UNAME,UPASS,DBNAME);
return self::$_instance;
}
/**
* 連接數據庫方法
* @param $host 服務器地址
* @param $username 數據庫賬號
* @param $userpass 數據庫密碼
* @param $dbname 操作的數據庫名
*/
protected static function connect($host,$username,$userpass,$dbname){
try{
self::$_link = new PDO("mysql:host={$host};dbname={$dbname}",$username,$userpass);
//設置返回數據的類型
self::$_link->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
//設置操作數據庫的報錯模式
// self::$_link->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING);
// if(self::$_link){
// echo '連接數據庫成功';
// }
}catch (PDOException $e){
MyException::showError($e->getMessage());
}
}
/**
* 直接執行sql語句查詢數據庫的方法
* @param $sql mysql語句
* @param array $where 條件數據
* @return mixed 成功數組
*/
public function queryString($sql,$where=array()){
try{
//使用預處理語句來執行sql
$stmt = self::$_link->prepare($sql);
//判斷是否有條件數組
if(empty($where)){
$stmt->execute();
}else{
$stmt->execute($where);
}
//判斷執行是否成功
if($stmt->rowCount() > 0){
return $stmt->fetchAll();
}else {
//得到錯誤信息
$err = $stmt->errorInfo();
throw new PDOException($err[2]);
}
}catch(PDOException $e){
MyException::showError($e->getMessage());
}
}
/**
* 內部sql處理好的查詢方法
* @param $table 表名
* @param array $where 查詢條件
* @return mixed 成功返回數組
*/
public function select($table,$where = array()){
$sql = "select * from {$table} ";
if(!empty($this->whereStr)){
$sql .= $this->whereStr;
}
try{
//執行sql語句
$stmt = self::$_link->prepare($sql);
if(empty($where)){
$stmt->execute();
}else{
$stmt->execute($where);
}
//判斷是否成功,如果不成功爆出異常
if($stmt->rowCount() > 0){
return $stmt->fetchAll();
}else{
$err = $stmt->errorInfo();
return $err[2];
}
}catch(PDOException $e){
MyException::showError($e->getMessage());
}
}
/**
* where條件方法
* @param string $whereStr
* @return $this
*/
public function where($whereStr = ''){
$this->whereStr = $whereStr;
return $this;//返回當前對象
}
/**
* 查詢單條數據的方法
* @param $table 表名
* @param array $where 查詢的條件,:key=value
* @return mixed 成功返回數組
*/
public function find($table,$where = array()){
$sql = "select * from {$table} ";
if(!empty($this->whereStr)){
$sql .= $this->whereStr;
}
try{
//執行sql
$stmt = self::$_link->prepare($sql);
if(empty($where)){
$stmt->execute();
}else{
$stmt->execute($where);
}
//判斷是否成功
if($stmt->rowCount() > 0){
$result = $stmt->fetchAll();
return $result[0];
}else{
$err = $stmt->errorInfo();
throw new PDOException($err[2]);
}
}catch(PDOException $e){
MyException::showError($e->getMessage());
}
}
/**
* 添加單條數據的方法
* @param $table 表名
* @param array(':username'=>'zhang6',':userpass'=>md5(123456),':create_time'=>time()) $data
* @return int 成功返回1
*/
public function insert($table,array $data){
$sql = "insert into {$table} ";
$fields = "";
$values = "";
foreach($data as $k => $v){
$fields .= ltrim($k,":").",";
$values .= "'".ltrim($v,":")."',";
}
$sql .= "(".rtrim($fields,",").") values (".rtrim($values,",").")";
try{
//開啟事務
self::$_link->beginTransaction();
$stmt = self::$_link->prepare($sql);
$stmt->execute($data);
if($stmt->rowCount() > 0){
self::$_link->commit();
return 1;
}else{
self::$_link->rollback();
$err = $stmt->errorInfo();
throw new PDOException($err[2]);
}
}catch(PDOException $e){
MyException::showError($e->getMessage());
}
}
/**
* 更新數據
* @param $table 表名
* @param array $data array(':username'=>'lisi',':userpass'=>md5(456789));
* @param array $where array(':id'=>9);
* @return int
*/
public function update($table,array $data,array $where){
$sql = "update {$table} set ";
$set_str = '';
foreach($data as $k => $v){
$set_str .= ltrim($k,":")."=$k,";
}
$sql .= rtrim($set_str,',').' '.$this->whereStr;
try{
self::$_link->beginTransaction();
$stmt = self::$_link->prepare($sql);
$data2 = array_merge($data,$where);
$stmt->execute($data2);
if($stmt->rowCount() > 0){
self::$_link->commit();
return 1;
}else{
self::$_link->rollback();
$err = $stmt->errorInfo();
throw new PDOException($err[2]);
}
}catch(PDOException $e){
MyException::showError($e->getMessage());
}
}
/**
* 刪除數據方法
* @param $table 表名
* @param array $where
* @return int
*/
public function delete($table,array $where){
$sql = "delete from {$table} ".$this->whereStr;
try{
self::$_link->beginTransaction();
$stmt = self::$_link->prepare($sql);
$stmt->execute($where);
if($stmt->rowCount() > 0){
self::$_link->commit();
return 1;
}else{
self::$_link->rollback();
$err = $stmt->errorInfo();
throw new PDOException($err[2]);
}
}catch(PDOException $e){
MyException::showError($e->getMessage());
}
}
/**
* 析構方法
* 銷毀對象
*/
public function __destruct(){
self::$_link = null;
}
}
```
然后我們開始進行測試
```cpp
|-index.php 項目前臺入口文件,單一入口
<?php
/**
* 項目前臺入口文件
* User: find35.com
* Date: 15/12/24
* Time: 下午5:15
*/
echo "<meta charset='utf-8'>";
require_once 'core/App.class.php';
require_once 'config/constants.php';
//注冊一個
define('APP','app');
spl_autoload_register(array('App','myAutoloader'));
try{
App::run();
}catch(MyException $e){
$e->showError($e->getMessage());
}
$db = Model::getStringleton();
//直接執行sql語句
//$result = $db->queryString('select * from users where username=:username',array(':username'=>'zhang'));
//查詢某個表
//$result = $db->select('users');
//查詢某個表,并增加where條件
//$result = $db->where('where username=:username')->select('users',array(':username'=>'zhang'));
//查詢單條數據
//$result = $db->where('where id=:id')->find('users',array(':id'=>'3'));
//插入數據
//$data = array(':username'=>'zhang6',':userpass'=>md5(123456),':create_time2'=>time());
//$result = $db->insert('users',$data);
//更新數據
//$data = array(':username'=>'lisi',':userpass'=>md5(456789));
//$where = array(':id'=>9);
//$result = $db->where('where id=:id')->update('users',$data,$where);
//刪除數據
$result = $db->where('where id=:id')->delete('users',array('id'=>9));
echo "<pre>";
print_r($result);
```
如果結果都是1,那么表示都成功了。