>  기사  >  php教程  >  PHP 프레임워크를 단계별로 작성하고 MVC 작업 프로세스에 대한 심층적인 이해를 얻으세요.

PHP 프레임워크를 단계별로 작성하고 MVC 작업 프로세스에 대한 심층적인 이해를 얻으세요.

WBOY
WBOY원래의
2016-09-19 08:55:001299검색

1 MVC란

MVC 패턴(Model-View-Controller)은 소프트웨어 엔지니어링의 소프트웨어 아키텍처 패턴으로, 소프트웨어 시스템을 세 가지 기본 부분으로 나눕니다. 모델 (모델), 보기(보기) 및 컨트롤러(컨트롤러).

PHP의 MVC 패턴은 웹 MVC라고도 하며 1970년대부터 발전했습니다. MVC의 목적은 프로그램의 후속 수정, 확장 및 단순화를 용이하게 하고 프로그램의 특정 부분을 재사용할 수 있도록 하는 동적 프로그래밍 설계를 구현하는 것입니다. 또한 이 모드는 복잡성을 단순화하여 프로그램 구조를 보다 직관적으로 만듭니다. 소프트웨어 시스템은 기본 부분을 분리하는 동시에 각 기본 부분에 적절한 기능을 제공합니다.

MVC 각 부분의 기능:

  • 모델대부분의 비즈니스 로직모든 데이터베이스 로직을 관리합니다. 모델은 데이터베이스에 연결하고 조작하기 위한 추상화 계층을 제공합니다.
  • 컨트롤러 - 사용자 요청에 응답하고, 데이터를 준비하고, 데이터 표시 방법을 결정하는 역할을 담당합니다.
  • 보기데이터 렌더링을 담당하고 이를 HTML을 통해 사용자에게 표시합니다.

PHP 프레임워크를 단계별로 작성하고 MVC 작업 프로세스에 대한 심층적인 이해를 얻으세요.

일반적인 웹 MVC 프로세스:

  1. 컨트롤러가 사용자가 보낸 요청을 가로챕니다.
  2. 컨트롤러는 모델을 호출하여 상태 읽기 및 쓰기 작업을 완료합니다.
  3. 컨트롤러가 View에 데이터를 전달합니다.
  4. View는 최종 결과를 렌더링하여 사용자에게 보여줍니다.

2 자체 MVC 프레임워크를 개발해야 하는 이유

인터넷에는 우수한 MVC 프레임워크가 많이 있습니다. 이 튜토리얼은 포괄적이고 궁극적인 MVC 프레임워크 솔루션을 개발하기 위한 것이 아니라 그 과정에서 PHP를 배울 수 있는 좋은 기회로 간주됩니다. , 객체 지향 프로그래밍MVC 디자인 패턴을 배우고, 개발의 몇 가지 측면을 배우게 됩니다.

게다가 프레임워크를 완전히 제어할 수 있으며 자신의 아이디어를 개발하는 프레임워크에 통합할 수 있습니다. 꼭 잘 되는 것은 아니지만, 자신만의 방식으로 기능과 모듈을 개발할 수 있습니다.

3 자신만의 MVC 프레임워크 개발 시작하기

3.1 디렉토리 준비

개발을 시작하기 전에 먼저 프로젝트를 설정해 보겠습니다. 우리가 빌드하는 프로젝트가 todo이고 MVC 프레임워크 이름이 FastPHP라고 가정합니다. 그런 다음 먼저 디렉터리 구조를 설정합니다.

PHP MVC简单目录

이 튜토리얼에서는 위 디렉토리가 모두 사용되지는 않지만 향후 프로그램 확장성을 위해 시작 부분에 프로그램 디렉토리를 설정하는 것이 매우 필요합니다. 각 디렉터리의 역할에 대해 자세히 알아보겠습니다.

  • 애플리케이션 – 애플리케이션 코드
  • config – 프로그램 구성 또는 데이터베이스 구성
  • fastphp - 프레임워크 코어 디렉토리
  • 공개 – 정적 파일
  • 런타임 - 임시 데이터 디렉터리
  • 스크립트 – 명령줄 도구

3.2 코드 사양

디렉터리를 설정한 후 코드 사양을 규정해야 합니다.

  1. MySQL的表名需小写,如:item,car
  2. 模块名(Models)需首字母大写,,并在名称后添加“Model”,如:ItemModel,CarModel
  3. 控制器(Controllers)需首字母大写,,并在名称中添加“Controller”,如:ItemController,CarController
  4. 视图(Views)部署结构为“控制器名/行为名”,如:item/view.php,car/buy.php

上述的一些规则是为了能在程序中更好的进行互相的调用。接下来就开始真正的PHP MVC编程了。

3.3 重定向

将所有的数据请求都重定向 index.php 文件,在 todo 目录下新建一个 .htaccess 文件,文件内容为:

<span class="hljs-section"><IfModule mod_rewrite.c>
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteEngine <span class="hljs-literal">On

    <span class="hljs-comment"># 确保请求路径不是一个文件名或目录
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond <span class="hljs-variable">%{REQUEST_FILENAME} !-f
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond <span class="hljs-variable">%{REQUEST_FILENAME} !-d

    <span class="hljs-comment"># 重定向所有请求到 index.php?url=PATHNAME
    <span class="hljs-attribute"><span class="hljs-nomarkup">RewriteRule ^(.*)$ index.php?url=<span class="hljs-number">$1<span class="hljs-meta"> [PT,L]
<span class="hljs-section"></IfModule>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
这样做的主要原因有:
  1. 程序有一个单一的入口;
  2. 除静态程序,其他所有程序都重定向到 index.php 上;
  3. 可以用来生成利于SEO的URL,想要更好的配置URL,后期可能会需要URL路由,这里先不做介绍了。

3.4 入口文件

做完上面的操作,就应该知道我们需要做什么了,没错!在 public 目录下添加 index.php 文件,文件内容为:

<span class="php"><span class="hljs-meta"><?php 

<span class="hljs-comment">// 应用目录为当前目录
define(<span class="hljs-string">'APP_PATH', <span class="hljs-keyword">__DIR__.<span class="hljs-string">'/');

<span class="hljs-comment">// 开启调试模式
define(<span class="hljs-string">'APP_DEBUG', <span class="hljs-keyword">true);

<span class="hljs-comment">// 网站根URL
define(<span class="hljs-string">'APP_URL', <span class="hljs-string">'http://localhost/fastphp');

<span class="hljs-comment">// 加载框架
<span class="hljs-keyword">require <span class="hljs-string">'./fastphp/FastPHP.php';
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
注意,上面的PHP代码中,并没有添加PHP结束符号”?>”,这么做的主要原因是,对于只有 PHP 代码的文件,结束标志(“?>”)最好不存在,PHP自身并不需要结束符号,不添加结束符号可以很大程度上防止末尾被添加额外的注入内容,让程序更加安全。

3.5 配置文件和主请求

在 index.php 中,我们对 fastphp  文件夹下的 FastPHP.php 发起了请求,那么 FastPHP.php 这个启动文件中到底会包含哪些内容呢?

<span class="php"><span class="hljs-meta"><?php

<span class="hljs-comment">// 初始化常量
defined(<span class="hljs-string">'FRAME_PATH') <span class="hljs-keyword">or define(<span class="hljs-string">'FRAME_PATH', <span class="hljs-keyword">__DIR__.<span class="hljs-string">'/');
defined(<span class="hljs-string">'APP_PATH') <span class="hljs-keyword">or define(<span class="hljs-string">'APP_PATH', dirname($_SERVER[<span class="hljs-string">'SCRIPT_FILENAME']).<span class="hljs-string">'/');
defined(<span class="hljs-string">'APP_DEBUG') <span class="hljs-keyword">or define(<span class="hljs-string">'APP_DEBUG', <span class="hljs-keyword">false);
defined(<span class="hljs-string">'CONFIG_PATH') <span class="hljs-keyword">or define(<span class="hljs-string">'CONFIG_PATH', APP_PATH.<span class="hljs-string">'config/');
defined(<span class="hljs-string">'RUNTIME_PATH') <span class="hljs-keyword">or define(<span class="hljs-string">'RUNTIME_PATH', APP_PATH.<span class="hljs-string">'runtime/');

<span class="hljs-comment">// 包含配置文件
<span class="hljs-keyword">require APP_PATH . <span class="hljs-string">'config/config.php';

<span class="hljs-comment">//包含核心框架类
<span class="hljs-keyword">require FRAME_PATH . <span class="hljs-string">'Core.php';

<span class="hljs-comment">// 实例化核心类
$fast = <span class="hljs-keyword">new Core;
$fast->run();
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
 以上文件都其实可以直接在 index.php 文件中包含,常量也可以直接在 index.php 中定义,我们这么做的原因是为了在后期管理和拓展中更加的方便,所以把需要在一开始的时候就加载运行的程序统一放到一个单独的文件中引用。

先来看看config文件下的 config .php 文件,该文件的主要作用是设置一些程序的配置项及数据库连接等,主要内容为:

<span class="php"><span class="hljs-meta"><?php
 
<span class="hljs-comment">/** 变量配置 **/
 
define(<span class="hljs-string">'DB_NAME', <span class="hljs-string">'todo');
define(<span class="hljs-string">'DB_USER', <span class="hljs-string">'root');
define(<span class="hljs-string">'DB_PASSWORD', <span class="hljs-string">'root');
define(<span class="hljs-string">'DB_HOST', <span class="hljs-string">'localhost');
</span></span></span></span></span></span></span></span></span></span></span>
应该说 config.php 涉及到的内容并不多,不过是一些基础数据库的设置,再来看看 fastphp下的共用框架入口文件 Core.php 应该怎么写。
<span class="php"><span class="hljs-meta"><?php
<span class="hljs-comment">/**
 * FastPHP核心框架
 */
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Core
{
    <span class="hljs-comment">// 运行程序
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">run<span class="hljs-params">()
    {
        spl_autoload_register(<span class="hljs-keyword">array($this, <span class="hljs-string">'loadClass'));
        $this->setReporting();
        $this->removeMagicQuotes();
        $this->unregisterGlobals();
        $this->Route();
    }

    <span class="hljs-comment">// 路由处理
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">Route<span class="hljs-params">()
    {
        $controllerName = <span class="hljs-string">'Index';
        $action = <span class="hljs-string">'index';

        <span class="hljs-keyword">if (!<span class="hljs-keyword">empty($_GET[<span class="hljs-string">'url'])) {
            $url = $_GET[<span class="hljs-string">'url'];
            $urlArray = explode(<span class="hljs-string">'/', $url);
            
            <span class="hljs-comment">// 获取控制器名
            $controllerName = ucfirst($urlArray[<span class="hljs-number">0]);
            
            <span class="hljs-comment">// 获取动作名
            array_shift($urlArray);
            $action = <span class="hljs-keyword">empty($urlArray[<span class="hljs-number">0]) ? <span class="hljs-string">'index' : $urlArray[<span class="hljs-number">0];
            
            <span class="hljs-comment">//获取URL参数
            array_shift($urlArray);
            $queryString = <span class="hljs-keyword">empty($urlArray) ? <span class="hljs-keyword">array() : $urlArray;
        }

        <span class="hljs-comment">// 数据为空的处理
        $queryString  = <span class="hljs-keyword">empty($queryString) ? <span class="hljs-keyword">array() : $queryString;

        <span class="hljs-comment">// 实例化控制器
        $controller = $controllerName . <span class="hljs-string">'Controller';
        $dispatch = <span class="hljs-keyword">new $controller($controllerName, $action);

        <span class="hljs-comment">// 如果控制器存和动作存在,这调用并传入URL参数
        <span class="hljs-keyword">if ((int)method_exists($controller, $action)) {
            call_user_func_array(<span class="hljs-keyword">array($dispatch, $action), $queryString);
        } <span class="hljs-keyword">else {
            <span class="hljs-keyword">exit($controller . <span class="hljs-string">"控制器不存在");
        }
    }

    <span class="hljs-comment">// 检测开发环境
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">setReporting<span class="hljs-params">()
    {
        <span class="hljs-keyword">if (APP_DEBUG === <span class="hljs-keyword">true) {
            error_reporting(E_ALL);
            ini_set(<span class="hljs-string">'display_errors',<span class="hljs-string">'On');
        } <span class="hljs-keyword">else {
            error_reporting(E_ALL);
            ini_set(<span class="hljs-string">'display_errors',<span class="hljs-string">'Off');
            ini_set(<span class="hljs-string">'log_errors', <span class="hljs-string">'On');
            ini_set(<span class="hljs-string">'error_log', RUNTIME_PATH. <span class="hljs-string">'logs/error.log');
        }
    }

    <span class="hljs-comment">// 删除敏感字符
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">stripSlashesDeep<span class="hljs-params">($value)
    {
        $value = is_array($value) ? array_map(<span class="hljs-string">'stripSlashesDeep', $value) : stripslashes($value);
        <span class="hljs-keyword">return $value;
    }

    <span class="hljs-comment">// 检测敏感字符并删除
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">removeMagicQuotes<span class="hljs-params">()
    {
        <span class="hljs-keyword">if ( get_magic_quotes_gpc()) {
            $_GET = stripSlashesDeep($_GET );
            $_POST = stripSlashesDeep($_POST );
            $_COOKIE = stripSlashesDeep($_COOKIE);
            $_SESSION = stripSlashesDeep($_SESSION);
        }
    }

    <span class="hljs-comment">// 检测自定义全局变量(register globals)并移除
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">unregisterGlobals<span class="hljs-params">()
    {
        <span class="hljs-keyword">if (ini_get(<span class="hljs-string">'register_globals')) {
            $array = <span class="hljs-keyword">array(<span class="hljs-string">'_SESSION', <span class="hljs-string">'_POST', <span class="hljs-string">'_GET', <span class="hljs-string">'_COOKIE', <span class="hljs-string">'_REQUEST', <span class="hljs-string">'_SERVER', <span class="hljs-string">'_ENV', <span class="hljs-string">'_FILES');
           <span class="hljs-keyword">foreach ($array <span class="hljs-keyword">as $value) {
                <span class="hljs-keyword">foreach ($GLOBALS[$value] <span class="hljs-keyword">as $key => $var) {
                    <span class="hljs-keyword">if ($var === $GLOBALS[$key]) {
                        <span class="hljs-keyword">unset($GLOBALS[$key]);
                    }
                }
            }
        }
    }

    <span class="hljs-comment">// 自动加载控制器和模型类 
    <span class="hljs-keyword">static <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">loadClass<span class="hljs-params">($class)
    {
        $frameworks = FRAME_PATH . $class . <span class="hljs-string">'.class.php';
        $controllers = APP_PATH . <span class="hljs-string">'application/controllers/' . $class . <span class="hljs-string">'.class.php';
        $models = APP_PATH . <span class="hljs-string">'application/models/' . $class . <span class="hljs-string">'.class.php';

        <span class="hljs-keyword">if (file_exists($frameworks)) {
            <span class="hljs-comment">// 加载框架核心类
            <span class="hljs-keyword">include $frameworks;
        } <span class="hljs-keyword">elseif (file_exists($controllers)) {
            <span class="hljs-comment">// 加载应用控制器类
            <span class="hljs-keyword">include $controllers;
        } <span class="hljs-keyword">elseif (file_exists($models)) {
            <span class="hljs-comment">//加载应用模型类
            <span class="hljs-keyword">include $models;
        } <span class="hljs-keyword">else {
            <span class="hljs-comment">/* 错误代码 */
        }
    }
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

下面重点讲解主请求方法 callHook(),首先我们想看看我们的 URL 会这样:

yoursite.com/controllerName/actionName/queryString

callHook()的作用就是,从全局变量 $_GET['url']变量中获取 URL,并将其分割成三部分:$controller、$action 和 $queryString。

例如,URL链接为:todo.com/item/view/1/first-item,那么

  • $controller 就是:item
  • $action 就是:view
  • 查询字符串Query String就是:array(1, first-item)

分割完成后,会实例化一个新的控制器:$controller.'Controller'(其中“.”是连字符),并调用其方法 $action。

3.6 控制器/Controller基类

接下来的操作就是在 fastphp 中建立程序所需的基类,包括控制器模型视图的基类。

新建控制器基类为 Controller.class.php,控制器的主要功能就是总调度,具体具体内容如下:

<span class="php"><span class="hljs-meta"><?php 
<span class="hljs-comment">/**
 * 控制器基类
 */
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Controller
{
    <span class="hljs-keyword">protected $_controller;
    <span class="hljs-keyword">protected $_action;
    <span class="hljs-keyword">protected $_view;
 
    <span class="hljs-comment">// 构造函数,初始化属性,并实例化对应模型
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__construct<span class="hljs-params">($controller, $action)
    {
        $this->_controller = $controller;
        $this->_action = $action;
        $this->_view = <span class="hljs-keyword">new View($controller, $action);
    }

    <span class="hljs-comment">// 分配变量
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">assign<span class="hljs-params">($name, $value)
    {
        $this->_view->assign($name, $value);
    }

    <span class="hljs-comment">// 渲染视图
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__destruct<span class="hljs-params">()
    {
        $this->_view->render();
    }
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

Controller 类实现所有控制器、模型和视图(View类)的通信。在执行析构函数时,我们可以调用 render() 来显示视图(view)文件。

3.7 模型Model基类

新建模型基类为 Model.class.php,模型基类 Model.class.php 代码如下:

<span class="php"><span class="hljs-meta"><?php

<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Model <span class="hljs-keyword">extends <span class="hljs-title">Sql
{
    <span class="hljs-keyword">protected $_model;
    <span class="hljs-keyword">protected $_table;
 
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__construct<span class="hljs-params">()
    {
        <span class="hljs-comment">// 连接数据库
        $this->connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
        
        <span class="hljs-comment">// 获取模型名称
        $this->_model = get_class($this);
        $this->_model = rtrim($this->_model, <span class="hljs-string">'Model');
        
        <span class="hljs-comment">// 数据库表名与类名一致
        $this->_table = strtolower($this->_model);
    }
 
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__destruct<span class="hljs-params">()
    {
    }
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

考虑到模型需要对数据库进行处理,所以单独建立一个数据库基类 Sql.class.php,模型基类继承 Sql.class.php,代码如下:

<span class="php"><span class="hljs-meta"><?php 

<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Sql
{
    <span class="hljs-keyword">protected $_dbHandle;
    <span class="hljs-keyword">protected $_PHP 프레임워크를 단계별로 작성하고 MVC 작업 프로세스에 대한 심층적인 이해를 얻으세요.;

    <span class="hljs-comment">// 连接数据库
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">connect<span class="hljs-params">($host, $user, $pass, $dbname)
    {
        <span class="hljs-keyword">try {
            $dsn = sprintf(<span class="hljs-string">"mysql:host=%s;dbname=%s;charset=utf8", $host, $dbname);
            $this->_dbHandle = <span class="hljs-keyword">new PDO($dsn, $user, $pass, <span class="hljs-keyword">array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC));
        } <span class="hljs-keyword">catch (PDOException $e) {
            <span class="hljs-keyword">exit(<span class="hljs-string">'错误: ' . $e->getMessage());
        }
    }

    <span class="hljs-comment">// 查询所有
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">selectAll<span class="hljs-params">()
    {
        $sql = sprintf(<span class="hljs-string">"select * from `%s`", $this->_table);
        $sth = $this->_dbHandle->prepare($sql);
        $sth->execute();

        <span class="hljs-keyword">return $sth->fetchAll();
    }

    <span class="hljs-comment">// 根据条件 (id) 查询
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">select<span class="hljs-params">($id)
    {
        $sql = sprintf(<span class="hljs-string">"select * from `%s` where `id` = '%s'", $this->_table, $id);
        $sth = $this->_dbHandle->prepare($sql);
        $sth->execute();
        
        <span class="hljs-keyword">return $sth->fetch();
    }

    <span class="hljs-comment">// 根据条件 (id) 删除
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">delete<span class="hljs-params">($id)
    {
        $sql = sprintf(<span class="hljs-string">"delete from `%s` where `id` = '%s'", $this->_table, $id);
        $sth = $this->_dbHandle->prepare($sql);
        $sth->execute();

        <span class="hljs-keyword">return $sth->rowCount();
    }

    <span class="hljs-comment">// 自定义SQL查询,返回影响的行数
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">query<span class="hljs-params">($sql)
    {
        $sth = $this->_dbHandle->prepare($sql);
        $sth->execute();

        <span class="hljs-keyword">return $sth->rowCount();
    }

    <span class="hljs-comment">// 新增数据
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">add<span class="hljs-params">($data)
    {
        $sql = sprintf(<span class="hljs-string">"insert into `%s` %s", $this->_table, $this->formatInsert($data));

        <span class="hljs-keyword">return $this->query($sql);
    }

    <span class="hljs-comment">// 修改数据
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">update<span class="hljs-params">($id, $data)
    {
        $sql = sprintf(<span class="hljs-string">"update `%s` set %s where `id` = '%s'", $this->_table, $this->formatUpdate($data), $id);

        <span class="hljs-keyword">return $this->query($sql);
    }

    <span class="hljs-comment">// 将数组转换成插入格式的sql语句
    <span class="hljs-keyword">private <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">formatInsert<span class="hljs-params">($data)
    {
        $fields = <span class="hljs-keyword">array();
        $values = <span class="hljs-keyword">array();
        <span class="hljs-keyword">foreach ($data <span class="hljs-keyword">as $key => $value) {
            $fields[] = sprintf(<span class="hljs-string">"`%s`", $key);
            $values[] = sprintf(<span class="hljs-string">"'%s'", $value);
        }

        $field = implode(<span class="hljs-string">',', $fields);
        $value = implode(<span class="hljs-string">',', $values);

        <span class="hljs-keyword">return sprintf(<span class="hljs-string">"(%s) values (%s)", $field, $value);
    }

    <span class="hljs-comment">// 将数组转换成更新格式的sql语句
    <span class="hljs-keyword">private <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">formatUpdate<span class="hljs-params">($data)
    {
        $fields = <span class="hljs-keyword">array();
        <span class="hljs-keyword">foreach ($data <span class="hljs-keyword">as $key => $value) {
            $fields[] = sprintf(<span class="hljs-string">"`%s` = '%s'", $key, $value);
        }

        <span class="hljs-keyword">return implode(<span class="hljs-string">',', $fields);
    }
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

应该说,Sql.class.php 是框架的核心部分。为什么?因为通过它,我们创建了一个 SQL 抽象层,可以大大减少了数据库的编程工作。虽然 PDO 接口本来已经很简洁,但是抽象之后框架的可灵活性更高。

3.8 视图View类

视图类 View.class.php 内容如下:

<span class="php"><span class="hljs-meta"><?php
<span class="hljs-comment">/**
 * 视图基类
 */
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">View
{
    <span class="hljs-keyword">protected $variables = <span class="hljs-keyword">array();
    <span class="hljs-keyword">protected $_controller;
    <span class="hljs-keyword">protected $_action;

    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__construct<span class="hljs-params">($controller, $action)
    {
        $this->_controller = $controller;
        $this->_action = $action;
    }
 
    <span class="hljs-comment">/** 分配变量 **/
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">assign<span class="hljs-params">($name, $value)
    {
        $this->variables[$name] = $value;
    }
 
    <span class="hljs-comment">/** 渲染显示 **/
    <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">render<span class="hljs-params">()
    {
        extract($this->variables);
        $defaultHeader = APP_PATH . <span class="hljs-string">'application/views/header.php';
        $defaultFooter = APP_PATH . <span class="hljs-string">'application/views/footer.php';
        $controllerHeader = APP_PATH . <span class="hljs-string">'application/views/' . $this->_controller . <span class="hljs-string">'/header.php';
        $controllerFooter = APP_PATH . <span class="hljs-string">'application/views/' . $this->_controller . <span class="hljs-string">'/footer.php';
        
        <span class="hljs-comment">// 页头文件
        <span class="hljs-keyword">if (file_exists($controllerHeader)) {
            <span class="hljs-keyword">include ($controllerHeader);
        } <span class="hljs-keyword">else {
            <span class="hljs-keyword">include ($defaultHeader);
        }

        <span class="hljs-comment">// 页内容文件
        <span class="hljs-keyword">include (APP_PATH . <span class="hljs-string">'application/views/' . $this->_controller . <span class="hljs-string">'/' . $this->_action . <span class="hljs-string">'.php');
        
        <span class="hljs-comment">// 页脚文件
        <span class="hljs-keyword">if (file_exists($controllerFooter)) {
            <span class="hljs-keyword">include ($controllerFooter);
        } <span class="hljs-keyword">else {
            <span class="hljs-keyword">include ($defaultFooter);
        }
    }
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

这样我们的核心的PHP MVC框架就编写完成了,下面我们开始编写应用来测试框架功能。

4 应用

4.1 数据库部署

在 SQL 中新建一个 todo 数据库,使用下面的语句增加 item 数据表并插入2条记录:

<span class="hljs-keyword">CREATE <span class="hljs-keyword">DATABASE <span class="hljs-string">`todo` <span class="hljs-keyword">DEFAULT <span class="hljs-built_in">CHARACTER <span class="hljs-keyword">SET utf8 <span class="hljs-keyword">COLLATE utf8_general_ci;
<span class="hljs-keyword">USE <span class="hljs-string">`todo`;

<span class="hljs-keyword">CREATE <span class="hljs-keyword">TABLE <span class="hljs-string">`item` (
    <span class="hljs-string">`id` <span class="hljs-built_in">int(<span class="hljs-number">11) <span class="hljs-keyword">NOT <span class="hljs-literal">NULL auto_increment,
    <span class="hljs-string">`item_name` <span class="hljs-built_in">varchar(<span class="hljs-number">255) <span class="hljs-keyword">NOT <span class="hljs-literal">NULL,
    PRIMARY <span class="hljs-keyword">KEY (<span class="hljs-string">`id`)
) <span class="hljs-keyword">ENGINE=<span class="hljs-keyword">InnoDB AUTO_INCREMENT=<span class="hljs-number">1 <span class="hljs-keyword">DEFAULT <span class="hljs-keyword">CHARSET=utf8;
 
<span class="hljs-keyword">INSERT <span class="hljs-keyword">INTO <span class="hljs-string">`item` <span class="hljs-keyword">VALUES(<span class="hljs-number">1, <span class="hljs-string">'Hello World.');
<span class="hljs-keyword">INSERT <span class="hljs-keyword">INTO <span class="hljs-string">`item` <span class="hljs-keyword">VALUES(<span class="hljs-number">2, <span class="hljs-string">'Lets go!');</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

4.2 部署模型

然后,我们还需要在 models 目录中创建一个 ItemModel.php 模型,内容如下:

<span class="php"><span class="hljs-meta"><?php

<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">ItemModel <span class="hljs-keyword">extends <span class="hljs-title">Model
{
    <span class="hljs-comment">/* 业务逻辑层实现 */
}
</span></span></span></span></span></span></span></span>

模型内容为空。因为 Item 模型继承了 Model,所以它拥有 Model 的所有功能。

4.3 部署控制器

controllers 目录下创建一个 ItemController.php 控制器,内容如下:

<span class="php"><span class="hljs-meta"><?php
 
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">ItemController <span class="hljs-keyword">extends <span class="hljs-title">Controller
{
    <span class="hljs-comment">// 首页方法,测试框架自定义DB查询
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">index<span class="hljs-params">()
    {
        $items = (<span class="hljs-keyword">new ItemModel)->selectAll();

        $this->assign(<span class="hljs-string">'title', <span class="hljs-string">'全部条目');
        $this->assign(<span class="hljs-string">'items', $items);
    }
    
    <span class="hljs-comment">// 添加记录,测试框架DB记录创建(Create)
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">add<span class="hljs-params">()
    {
        $data[<span class="hljs-string">'item_name'] = $_POST[<span class="hljs-string">'value'];
        $count = (<span class="hljs-keyword">new ItemModel)->add($data);

        $this->assign(<span class="hljs-string">'title', <span class="hljs-string">'添加成功');
        $this->assign(<span class="hljs-string">'count', $count);
    }
    
    <span class="hljs-comment">// 查看记录,测试框架DB记录读取(Read)
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">view<span class="hljs-params">($id = null)
    {
        $item = (<span class="hljs-keyword">new ItemModel)->select($id);

        $this->assign(<span class="hljs-string">'title', <span class="hljs-string">'正在查看' . $item[<span class="hljs-string">'item_name']);
        $this->assign(<span class="hljs-string">'item', $item);
    }
    
    <span class="hljs-comment">// 更新记录,测试框架DB记录更新(Update)
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">update<span class="hljs-params">()
    {
        $data = <span class="hljs-keyword">array(<span class="hljs-string">'id' => $_POST[<span class="hljs-string">'id'], <span class="hljs-string">'item_name' => $_POST[<span class="hljs-string">'value']);
        $count = (<span class="hljs-keyword">new ItemModel)->update($data[<span class="hljs-string">'id'], $data);

        $this->assign(<span class="hljs-string">'title', <span class="hljs-string">'修改成功');
        $this->assign(<span class="hljs-string">'count', $count);
    }
    
    <span class="hljs-comment">// 删除记录,测试框架DB记录删除(Delete)
    <span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">delete<span class="hljs-params">($id = null)
    {
        $count = (<span class="hljs-keyword">new ItemModel)->delete($id);

        $this->assign(<span class="hljs-string">'title', <span class="hljs-string">'删除成功');
        $this->assign(<span class="hljs-string">'count', $count);
    }
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

4.4 部署视图

views 目录下新建 header.php 和 footer.php 两个页头页脚模板,内容如下。

header.php,内容:

<span class="hljs-tag"><<span class="hljs-name">html>
<span class="hljs-tag"><<span class="hljs-name">head>
    <span class="hljs-tag"><<span class="hljs-name">meta <span class="hljs-attr">http-equiv=<span class="hljs-string">"Content-Type" <span class="hljs-attr">content=<span class="hljs-string">"text/html; charset=utf-8" />
    <span class="hljs-tag"><<span class="hljs-name">title><span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $title <span class="hljs-meta">?><span class="hljs-tag"></<span class="hljs-name">title>
    <span class="hljs-tag"><<span class="hljs-name">style><span class="css">
        <span class="hljs-selector-class">.item {
            <span class="hljs-attribute">width:<span class="hljs-number">400px;
        }
 
        <span class="hljs-selector-tag">input {
            <span class="hljs-attribute">color:<span class="hljs-number">#222222;
            <span class="hljs-attribute">font-family:georgia,times;
            <span class="hljs-attribute">font-size:<span class="hljs-number">24px;
            <span class="hljs-attribute">font-weight:normal;
            <span class="hljs-attribute">line-height:<span class="hljs-number">1.2em;
            <span class="hljs-attribute">color:black;
        }
 
        <span class="hljs-selector-tag">a {
            <span class="hljs-attribute">color:blue;
            <span class="hljs-attribute">font-family:georgia,times;
            <span class="hljs-attribute">font-size:<span class="hljs-number">20px;
            <span class="hljs-attribute">font-weight:normal;
            <span class="hljs-attribute">line-height:<span class="hljs-number">1.2em;
            <span class="hljs-attribute">text-decoration:none;
         }
 
        <span class="hljs-selector-tag">a<span class="hljs-selector-pseudo">:hover {
            <span class="hljs-attribute">text-decoration:underline;
        }

        <span class="hljs-selector-tag">h1 {
            <span class="hljs-attribute">color:<span class="hljs-number">#000000;
            <span class="hljs-attribute">font-size:<span class="hljs-number">41px;
            <span class="hljs-attribute">letter-spacing:-<span class="hljs-number">2px;
            <span class="hljs-attribute">line-height:<span class="hljs-number">1em;
            <span class="hljs-attribute">font-family:helvetica,arial,sans-serif;
            <span class="hljs-attribute">border-bottom:<span class="hljs-number">1px dotted <span class="hljs-number">#cccccc;
        }
 
        <span class="hljs-selector-tag">h2 {
            <span class="hljs-attribute">color:<span class="hljs-number">#000000;
            <span class="hljs-attribute">font-size:<span class="hljs-number">34px;
            <span class="hljs-attribute">letter-spacing:-<span class="hljs-number">2px;
            <span class="hljs-attribute">line-height:<span class="hljs-number">1em;
            <span class="hljs-attribute">font-family:helvetica,arial,sans-serif;
        }
    <span class="hljs-tag"></<span class="hljs-name">style>
<span class="hljs-tag"></<span class="hljs-name">head>
<span class="hljs-tag"><<span class="hljs-name">body>
    <span class="hljs-tag"><<span class="hljs-name">h1><span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $title <span class="hljs-meta">?><span class="hljs-tag"></<span class="hljs-name">h1>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

footer.php,内容:

<span class="hljs-section"></body>
<span class="hljs-section"></html>
</span></span>

然后,在 views/item 创建以下几个视图文件。

index.php,浏览数据库内 item 表的所有记录,内容:

<span class="hljs-tag"><<span class="hljs-name">form <span class="hljs-attr">action=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/add" <span class="hljs-attr">method=<span class="hljs-string">"post">
    <span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"text" <span class="hljs-attr">value=<span class="hljs-string">"点击添加" <span class="hljs-attr">onclick=<span class="hljs-string">"this.value=''" <span class="hljs-attr">name=<span class="hljs-string">"value">
    <span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"submit" <span class="hljs-attr">value=<span class="hljs-string">"添加">
<span class="hljs-tag"></<span class="hljs-name">form>
<span class="hljs-tag"><<span class="hljs-name">br/><span class="hljs-tag"><<span class="hljs-name">br/>

<span class="php"><span class="hljs-meta"><?php $number = <span class="hljs-number">0<span class="hljs-meta">?>
 
<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">foreach ($items <span class="hljs-keyword">as $item): <span class="hljs-meta">?>
    <span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/view/<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'id'] <span class="hljs-meta">?>" <span class="hljs-attr">title=<span class="hljs-string">"点击修改">
        <span class="hljs-tag"><<span class="hljs-name">span <span class="hljs-attr">class=<span class="hljs-string">"item">
            <span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo ++$number <span class="hljs-meta">?>
            <span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'item_name'] <span class="hljs-meta">?>
        <span class="hljs-tag"></<span class="hljs-name">span>
    <span class="hljs-tag"></<span class="hljs-name">a>
    ----
    <span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/delete/<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'id']<span class="hljs-meta">?>">删除<span class="hljs-tag"></<span class="hljs-name">a>
<span class="hljs-tag"><<span class="hljs-name">br/>
<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">endforeach <span class="hljs-meta">?>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

add.php,添加记录,内容:

<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/index">成功添加<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $count <span class="hljs-meta">?>条记录,点击返回<span class="hljs-tag"></<span class="hljs-name">a>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

view.php,查看单条记录,内容:

<span class="hljs-tag"><<span class="hljs-name">form <span class="hljs-attr">action=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/update" <span class="hljs-attr">method=<span class="hljs-string">"post">
    <span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"text" <span class="hljs-attr">name=<span class="hljs-string">"value" <span class="hljs-attr">value=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'item_name'] <span class="hljs-meta">?>">
    <span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"hidden" <span class="hljs-attr">name=<span class="hljs-string">"id" <span class="hljs-attr">value=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'id'] <span class="hljs-meta">?>">
    <span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"submit" <span class="hljs-attr">value=<span class="hljs-string">"修改">
<span class="hljs-tag"></<span class="hljs-name">form>

<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/index">返回<span class="hljs-tag"></<span class="hljs-name">a>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

update.php,更改记录,内容:

<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/index">成功修改<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $count <span class="hljs-meta">?>项,点击返回<span class="hljs-tag"></<span class="hljs-name">a>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

delete.php,删除记录,内容:

<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/index">成功删除<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $count <span class="hljs-meta">?>项,点击返回<span class="hljs-tag"></<span class="hljs-name">a>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span>

4.5 应用测试

这样,在浏览器中访问 todo 程序:http://localhost/todo/item/index/,就可以看到效果了。

PHP 프레임워크를 단계별로 작성하고 MVC 작업 프로세스에 대한 심층적인 이해를 얻으세요.

위 코드는 모두 github에 공개되었으며, 주요 부분은 에어캐나다에서 댓글을 달았습니다. 창고 주소는 https://github.com/yeszao/fastphp입니다. 복제 및 제출을 환영합니다.

더 나은 MVC를 설계하거나 보다 표준화하여 사용하려면 "MVC 아키텍처의 책임 분할 원칙"을 참조하세요.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.