欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

PHP MVC框架【Myphp】的编写

程序员文章站 2022-06-12 23:48:47
1、什么是MVC MVC(Model-View-Controller)是软件工程的一种软件架构模式。 在MVC模式设计下,软件系统被分来三个模块:模型(Model)、视图(VIew)、控制器(Controller)。 PHP下的MVC模式又称为Web MVC,自上世纪70年代进化而来。 使用MVC模 ......

1、什么是mvc

mvc(model-view-controller)是软件工程的一种软件架构模式。

在mvc模式设计下,软件系统被分来三个模块:模型(model)、视图(view)、控制器(controller)。

php下的mvc模式又称为web mvc,自上世纪70年代进化而来。

使用mvc模式的目的是:实现一种动态的程序设计,便于后续对程序的修改和拓展,且使得程序的某一部分的重复利用成为可能。

mvc各模块的职能:

  • 模型model:管理大部分的业务逻辑和所有的数据库逻辑。模型抽象简化了连接和操作数据库的操作。
  • 控制器controller:负责响应用户请求、准备数据,决定如何展示数据。
  • 视图view:负责数据渲染,通过html方式呈现给用户。

PHP MVC框架【Myphp】的编写

一个典型的web mvc 处理流程:

  1. controller接受到用户发来的请求;
  2. controller调用model完成对状态的读写操作;
  3. controller把数据传递给view;
  4. view渲染出html页面并展示给用户。

2、为什么要自己开发mvc框架

为了做以mvc模式开发的各类cms的代码审计。

3、准备工作

3.1 开发环境准备

建站软件:phpstudy2018

ide:phpstorm2018.1

php版本:5.4.45-nts

apache&mysql

3.2 目录准备

我给该web mvc框架取名为:myphp

该项目目录为:myphpframe1

整个项目的目录结构如下:

myphpframe1           web框架部署根目录
├─application      应用目录
│  ├─controllers    控制器目录
│  ├─models        模块目录 
│  └─views        视图目录
├─config         配置文件目录
├─myphp           框架核心目录
├─runtime             运行临时目录
├─static              静态文件目录
├─.htaccess           apache目录配置
└─index.php           入口文件

myphpframe1位于apache站点根目录之下。通过访问 http://localhost/myphpframe1 ,可以访问到该项目。

3.3 重定向

 3.2展示的目录中.htaccess文件,是apache服务器的目录级别的分布式配置文件,可以针对特定目录改变apache配置。

.htaccess 可以帮我们实现:重写url、网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

apache服务器通过启用allowoverride all实现对应目录下的配置可重写。

本框架下.htaccess文件内容为:

 

<ifmodule mod_rewrite.c>
    #打开rerite功能
    rewriteengine on
    # 如果请求的是真实存在的文件f或目录d,直接访问
    rewritecond %{request_filename} !-f
    rewritecond %{request_filename} !-d
    #重定向所有请求到index.php?url=原路径
    rewriterule ^(.*)$ index.php?url=$1 [pt,l]
    #[pt] passthrough,使得rewriterule的结果重写加入到url的匹配中
    #[l] last,使得mod_rewrite 停止处理规则集
</ifmodule>

这里使用该.htaccess的原因是:

1、 静态文件可以直接访问,比如css文件、js文件都可以直接访问。

(如果是非index.php的php文件,可以访问,不过由于框架特性,类之间需要extends,可能会报错。如果是目录,也可以访问,如果apache开启了目录列表,则可以看到index of目录,否则返回403。)

2、 程序有了单一的入口,就是index.php。

  当请求地址不是真实存在的文件或目录时,请求就会传给index.php。

例如,访问地址:http://localhost/myphpframe1/item/index,文件系统中并不存在这样的文件或目录。则apache会把重写这个地址为:http://localhost/myphpframe1/index.php?url=item/index。这样在php中用$_get['url']就可以拿到 item/index了。

3.4 代码规范

代码规范如下:

  1. mysql的表名:使用小写字母与下划线(_)命名,如:item、bus_info
  2. model模块名:使用大驼峰法(首字母大写),并在名称后加上model,如:itemmodel、busmodel
  3. controller控制器名:使用大驼峰法(首字母大写),并在名称后加上controller,如:itemcontroller、buscontroller
  4. action方法名:使用小驼峰法(首字母小写),如:index、selectall
  5. view视图 部署结构为:控制器名/行为名,如:item/index.php、item/manage.php

使用代码规范的目的:使得程序能更好地相互调用。

4、php mvc核心框架

4.1 入口文件

index.php为整个项目的入口文件,位于项目根目录/下。

文件内容为:

<?php
header("content-type: text/html; charset=utf-8");
//设置返回包编码方式,避免页面乱码

//初始化常量
define('app_path',__dir__.'/');//网站根目录
define('config_path',app_path.'config/');//网站配置目录
define('app_debug',false);//开启调试模式
define('app_url','http://localhost/myphpframe1/');//网站url
define('runtime_path',app_path.'runtime/');//网站临时目录

//加载配置文件
require config_path.'/config.php';
//加载框架核心文件
require app_path.'myphp/myphp.php';

//实例化框架类,并执行run()方法
$myphp=new myphp();
$myphp->run();

 

可以看到,上面的php代码并没有使用php结束符 ?>。

纯php代码中php结束符是可选的,提倡不写php结束符。如果这个是一个被别人require的php文件,没有这个结束符,可以避免多余输出(也就是?>之后的任何数据,包括空格、换行符等)导致header, setcookie, session_start函数执行的失败(这几个函数执行前,不允许展示任何数据)。

4.2 配置文件

config.php是项目的配置文件。位于config/目录下。

config.php的作用是:定义数据库连接参数,配置默认控制器名和默认动作名。

config.php文件内容为:

<?php

//数据库连接参数
define('db_name','myphpdb');
define('db_user','root');
define('db_password','root');
define('db_host','localhost');

//默认控制器名和默认方法名
define('default_controller','item');
define('default_action','index');

4.3 框架核心类

myphp.php是myphp框架的核心类文件。位于myphp/目录下。

 在入口文件中,对框架类做了两步操作:实例化、调用run()方法。

run()方法调用了框架类自身方法,完成以下操作:

  1. 类自动重载
  2. 环境设置
  3. 清理转义字符
  4. 移除全局变量
  5. 处理路由

myphp.php文件内容为:

<?php
/**
 * myphp核心框架类
 */

//初始化常量
defined('app_path') or define('app_path',__dir__.'\\');
defined('app_url')or define('app_url','http://localhost/myphpframe1');
defined('app_debug') or define('app_debug',false);
defined('config_path') or define('config_path',app_path.'config\\');
defined('runtime_path') or define('runtime_path',app_path.'runtime/');
defined('default_controller') or define('default_controller','item');
defined('default_action') or define('default_action','index');

class myphp
{
    /**
     *运行程序
     */
    function run()
    {
        spl_autoload_register(array($this,'loadclass'));
        //spl_autoload_register — 注册给定的函数作为 __autoload 的实现
        //__autoload — 尝试加载未定义的类。当我们实例化一个未定义的类时,就会触发此函数
        $this->setreporting();
        $this->removemagicquotes();
        $this->unregisterglobals();
        $this->route();
    }

    /**
     *路由处理
     *abc.com/controllername/actionname/querystring
     * eg:
     * 访问url:localhost/item/show/name/1
     * 进入到route方法后,分割url,获得:
     * $controller:item
     * action:show
     * querystring:array(name,1)
     * 然后,实例化一个新控制器:itemcontroller,并调用itemcontroller->show()方法
     */
    function route()
    {
        $controllername=default_controller;
        $actionname=default_action;
        if(!empty($_get['url']))
        {
            $url=$_get['url'];//http://localhost/
            $urlarray=explode('/',$url);//explode 把字符串打散为数组
            //获取控制器名
            $controllername=ucfirst($urlarray[0]); //ucfirst 首字母转换为大写
            //获取动作名
            array_shift($urlarray);//array_shift 删除数组中的第一个元素,并返回被删除元素的值
            $actionname=empty($urlarray[0])?$actionname:$urlarray[0];
            //获取url参数
            array_shift($urlarray);
            $querystring=empty($urlarray[0])?array():$urlarray;
        }

        //url数据为空时
        $querystring=empty($querystring)?array():$querystring;

        //判断控制器、方法 是否存在
        $controller=$controllername.'controller';
        if(!class_exists($controller))//class_exists — 检查类是否已定义
        {
            exit($controller.'控制器不存在');
        }
        elseif(!method_exists($controller,$actionname))
        {
            exit($actionname.'方法不存在');
        }



        //实例化控制器,因为控制器对象里面
        //还会用到控制器名和操作名,所以实
        //例化的时候把他们俩的名称也传入。查看controller基类就明白。
        $dispatch=new $controller($controllername,$actionname);

        //$dispatch保存控制器实例化后的对象,我们就可以调用它的方法,也可以向方法中传入参数
        //call_user_func_array 调用回调函数,并把一个数组参数作为回调函数的参数
        //以下等同于:$dispatch->$action($querystring)
        call_user_func_array(array($dispatch,$actionname),$querystring);
    }

    /*
     * 设置开发环境
     * */
    function setreporting()
    {
        if(app_debug===true)
        {
            error_reporting(e_all); // 报告所有错误
            ini_set('display_errors','on');
            //ini_set 设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。
        }else{
            error_reporting(e_all);
            ini_set('display_errors','off');
            ini_set('log_errors','on');
            ini_set('error_log',runtime_path.'logs/error.log');
        }
    }

    /*
     * 删除多余的反斜杠
     */
    function stripslashesdeep($value)
    {
        $value=is_array($value)?array_map('stripslashesdeep',$value):stripslashes($value);
        // 递归调用
        // stripslashes — 返回一个去除转义反斜线后的字符串(\' 转换为 ' 等等)。双反斜线(\\)被转换为单个反斜线(\)
        //array_map — 为数组的每个元素应用回调函数
        return $value;
    }

    /*
     * 检测转义后的字符并清除反斜杠
    */
    function removemagicquotes()
    {
        //get_magic_quotes_gpc 获得php配置magic_quotes_gpc的bool值
        //如果开启magic_quotes_gpc,则对get、post、cookie 数据自动运行addslashes()
        //addslashes 在预定义字符之前添加反斜杠。预定义字符:单引号',双引号",反斜杠\,null
        //magic_quotes_gpc特性已自 php 5.3.0 起废弃并将自 php 5.4.0 起移除。所以在5.4版本以后php配置文件是找不到魔术引号的配置信息的
        //php 5.4之后,get_magic_quotes_gpc统一返回false
        if(get_magic_quotes_gpc())
        {
            $_get=$this->stripslashesdeep($_get);
            $_post=$this->stripslashesdeep($_post);
            $_cookie=$this->stripslashesdeep($_cookie);
            $_session=$this->stripslashesdeep($_session);
        }
    }

    /*
     * 检测自定义全局变量(register globals)并移除,模拟register_globals=off
    */
    function unregisterglobals()
    {
        /*
         * register_globals的意思就是注册为全局变量,5.4之后已被弃用。当register_globals=on时,
         * 局部变量的在脚本的全局域也可用(eg:$_get['a']也将以$a的形式存在)
         * 这样写是不好的实现,会影响代码中的其他变量
        */
        if(ini_get('register_globals'))
        {
            $array=array('_session','_post','_get','_cookie','_request','_server','_env','_files');
            foreach ($array as $value){
                echo $value;
                foreach($globals[$value]as $key=>$var)//处理每个内置数组中每个键值对
                {
                    if($var===$globals[$key]){//如果变量值等于全局变量中对应同名的变量值
                        unset($globals[$key]);//销毁对应的全局变量
                    }
                }
            }
        }
    }

    /*
     * 自动加载控制器和模型类
     */
    static function loadclass($class)
    {
        //echo '执行loadclass('.$class.')<br />';
        $frameworks=__dir__ . '\\'.$class.'.class.php';
        $controllers=app_path.'application\\controllers\\'.$class.'.php';
        $models=app_path.'application\\models\\'.$class.'.php';
        //echo $frameworks.'<br/>';
        //echo $controllers.'<br/>';
        //echo $models.'<br/>';
        if(file_exists($frameworks)){
            //加载核心框架类
            //echo '开始加载 框架核心类:'.$frameworks.'<br />';
            include $frameworks;
            //echo '成功加载 框架核心类:'.$frameworks.'<br />';
        }
        elseif (file_exists($controllers))
        {
            //echo '开始加载 应用控制器类:'.$controllers.'<br />';
            //加载应用控制器类else
            include $controllers;
            //echo '成功加载 应用控制器类:'.$controllers.'<br />';
        }
        elseif (file_exists($models))
        {
            //echo '开始加载 应用模型类:'.$models.'<br />';
            //加载应用模型类
            include $models;
            //echo '成功加载 应用模型类:'.$models.'<br />';
        }
        else{
            //加载失败代码
            exit('加载核心类文件失败!');
        }
        //echo 'loadclass('.$class.')结束<br />';
    }
}

讲解2个方法:loadclass()、route()

localclass()作用是:加载未定义的类时,导入对应的类文件。

首先构造对应类的可能的文件路径:如果对应类是核心框架类,则类文件路径应该为$frameworks;如果对应类是应用控制器类,则类文件路径应该为$controllers;如果对应类是应用模型类,则类文件路径应该为$models。

接着,对每个可能存在类文件路径,进行file_exists判定,存在则include。

则无本框架下任意类都可以完成自动加载。

 route()作用是:通过url,解析出控制器名、方法名和url参数,然后实例化对应的控制器,执行对应的方法,并传入对应的url参数。

假设浏览器访问的url为:yourhost.com/controllername/actionname/querystring

首先,apache会根据.htaccess重写url,重写后的url为:yourhost.com/index.php?url=controllername/actionname/querystring

route()从全局变量$_get['url']中获得字符串 controllername/actionname/querystring

然后,route()会将字符串转换为数组,通过对数组的操作获得3部分:controllernameactionname、querystring。

最后,route()会实例化对应控制器,并调用对应方法

例如,url链接为:yourhost.com/item/manage/6,经过route()处理后:   

  • $controllername为:item
  • $actionname为:manage
  • $urlarray为:array(6)

 处理完成后,route()会实例化控制器itemcontroller,并调用它的manage(array(6))

4.4 控制器controller基类

接下来,就是在myphp框架中创建mvc基类,包括控制器、模型、视图三个基类。

在myphp/目录下,新建一个控制器基类,文件名为controller.class.php,主要功能就是对整个程序进行调度,文件内容为:

<?php
/**
 * 控制器基类
 */

class controller
{
    protected $_controller;  //控制器名
    protected $_action;  //动作名
    protected $_view; //视图对象

    //构造函数:初始化属性,并实例化对应视图模型
    function __construct($controller,$action)
    {
        $this->_controller=$controller;
        $this->_action=$action;
        $this->_view=new view($controller,$action);
    }

    //分配变量
    //controller 类用assign()方法实现把变量保存到view对象中。
    //这样,应用controller调用父类controller的 $this->render()后,视图文件就可以显示这些变量。
    function assign($name,$value)
    {
        $this->_view->assign($name,$value);
    }

    //渲染视图
    function render()
    {
        // todo: implement __destruct() method.
        $this->_view->render();
    }
}

controller类通过 assign()方法 实现了变量从controller对象到view对象的传递(view类的assign就是将数据保存到自己数组中)。

这样,controller类在调用$this->render()后,视图对象就可以渲染展示这些变量了。

4.5 模型model基类

在myphp/目录下,新建一个模型基类,文件名为model.class.php,文件内容为:

<?php
/**
 * 模型基类
 */

class model extends sql
{
    protected $_model;
    protected $_table;

    function __construct()
    {
        //连接数据库
        $this->connect(db_host,db_user,db_password,db_name);
        //获取模型类名称
        $this->_model=get_class($this);
        $this->_model=rtrim($this->_model,'model');//rtrim 从字符串右侧移指定字符
        //模型类名称与数据库中的表名一致
        $this->_table=strtolower($this->_model);
    }
    function __destruct()
    {
        // todo: implement __destruct() method.
    }
}

可以看到,model基类继承了sql类。

因为数据操作比较复杂,所以我为这部分操作单独创建了一个sql类。

在myphp/目录下,新建一个sql类,文件名为sql.class.php,文件内容为:

<?php
/**
 * 数据库操作类
 */

class sql
{
    protected $_dbhandle;
    protected $_result;

    //连接数据库
    public function connect($host,$user,$pass,$dbname)
    {
        try{
            $dsn=sprintf("mysql:host=%s;dbname=%s;charset=utf8",$host,$dbname);//sprintf 把百分号(%)符号替换成一个作为参数进行传递的变量:
            $options=array(pdo::attr_default_fetch_mode=>pdo::fetch_assoc);
            //pdo::fetch_assoc:返回一个索引为结果集列名的数组
            $this->_dbhandle=new pdo($dsn,$user,$pass,$options);
        }
        catch(pdoexception $e)
        {
            exit('错误:'.$e->getmessage());
        }
    }

    //查询所有数据
    public function selectall()
    {
        $sql=sprintf("select * from `%s`",$this->_table);
        $sth=$this->_dbhandle->prepare($sql);
        $sth->execute();

        return $sth->fetchall();
    }

    //根据条件(id)查询
    public function select($id)
    {
        $sql=sprintf("select * from `%s` where `id`='%s'",$this->_table,$id);
        $sth=$this->_dbhandle->prepare($sql);
        $sth->execute();

        return $sth->fetch();
    }

    //根据条件(id)删除
    public function delete($id)
    {
        $sql=sprintf("delete from `%s` where `id`='%s'",$this->_table,$id);
        $sth=$this->_dbhandle->prepare();
        $sth->execute();

        return $sth->rowcount();
    }

    //自定义sql查询语句,返回影响的行数
    public function query($sql)
    {
        $sth=$this->_dbhandle->prepare($sql);
        $sth->execute($sql);

        return $sth->rowcount();
    }

    //新增数据
    public function add($data)
    {
        $sql=sprintf("insert into `%s` %s",$this->_table,$this->formatinsert($data));
        return $this->query($sql);
    }

    //修改数据
    public function update($id,$data)
    {
        $sql=sprintf("update `%s` set %s where `id`='%s'",$this->_table,$this->formatupdate($data),$id);
        return $this->query($sql);
    }

    //将数组转换为insert语句中的数据格式
    /*
    $array=array("id"=>1,"name"=>"jack","age"=>19);
    formatinsert($array)返回字符串:
    (`id`,`name`,`age`) values ('1','jack','19')

    */
    private function formatinsert($data)
    {
        $fields=array();
        $values=array();
        foreach($data as $key=>$value)
        {
            $fields[]=sprintf("`%s`",$key);
            $values[]=sprintf("'%s'",$value);
        }

        $filed=implode(',',$fields);//implode 把数组元素组合为字符串:
        $value=implode(',',$values);

        return sprintf("(%s) values (%s)",$filed,$value);
    }

    //将数组转换为update语句中的数据格式
    /*
    $array=array("name"=>"jack","age"=>19);
    formatupdate($array)返回字符串:
    `name`='1',`jack`='19'
    */
    private  function formatupdate($data)
    {
        $fields=array();
        foreach ($data as $key=>$value)
        {
            $fields[]=sprintf("`%s`='%s'",$key,$value);
        }
        return implode(',',$fields);
    }
}

4.6 视图view基类

在myphp/目录下,新建一个视图基类,文件名为view.class.php,文件内容为:

<?php
/**
 * 视图基类
 */

class view
{
    protected $variables=array();
    protected $_controller;
    protected $_action;

    function __construct($controller,$action)
    {
        $this->_controller=$controller;
        $this->_action=$action;
    }

    //导入变量
    function assign($name,$value)
    {
        $this->variables[$name]=$value;
    }

    //渲染显示
    function render()
    {
        extract($this->variables);
        //extract - 用来将一个数组分解成多个变量直接使用。
        $defaultheader=app_path.'application/views/header.php';
        $defaultfooter=app_path.'application/views/footer.php';
        $controllerheader=app_path.'application/views/'.$this->_controller.'/header.php';
        $controllerfooter=app_path.'application/views/'.$this->_controller.'/footer.php';

        //页头文件
        if(file_exists($controllerheader))
        {
            include ($controllerheader);
        }
        else {
            include ($defaultheader);
        }

        //页内容文件
        include (app_path.'application/views/'.$this->_controller.'/'.$this->_action.'.php');

        //页脚文件
        if(file_exists($controllerfooter))
        {
            include ($controllerfooter);
        } else {
            include ($defaultfooter);
        }
    }
}

至此,核心的php mvc框架核心就搭建完成了。

下面,我要编写基于框架的应用代码来测试这个框架的功能。

5、基于框架的应用

5.1 部署数据库

在sql中新建一个数据库 myphpdb,增加一个item表,并插入表中2个记录,sql命令如下:

create database `myphpdb` default character set utf8 collate utf8_general_ci;
use `myphpdb`;
create table `item`(
       `id` int(11) not null auto_increment,
       `item_name` varchar(255) not null,
       primary key (`id`)
)engine=innodb auto_increment=1 default charset=utf8;
insert into `item` values(1,'hello world.');
insert into `item` values(2,'let\'s go!');

5.2 部署模型

在application/models/目录下,创建一个itemmodel.php文件,主要功能是增加了检索数据的业务逻辑,文件内容为:

<?php
/**
 * 用户model
 */

class itemmodel extends model
{
    /**
     * 自定义当前模型操作的数据库表名称
     * 如果不指定,则默认为类名称的小写字符串,
     * 此处为item 表
     * */
    public $_table='item';

    /**
     * 搜索功能,以为sql父类中,并没有现成的like搜索
     * 所以需要自己写sql语句,对数据库的操作应该都放
     * 在model中,然后提供给controller直接调用
     */
    public function search($keyword)
    {
        $sql=sprintf("select * from `%s` where `item_name` like '%%%s%%'",$this->_table,$keyword);
        $sth=$this->_dbhandle->prepare($sql);
        $sth->execute();

        return $sth->fetchall();
    }
}

因为 item 模型继承了 model基类,所以它拥有 model 基类的所有功能。

5.3 部署控制器

在application/controllers/目录下,创建一个itemcontroller.php文件,主要功能是准备数据、调用对应的视图,文件内容为:

<?php
/**
 * item控制器类
 */

class itemcontroller extends controller
{
    //首页文件,测试myphp框架自定义的sql查询
    public function index()
    {
        $keyword=isset($_get['keyword'])?$_get['keyword']:'';
        if ($keyword)
        {
            $items=(new itemmodel())->search($keyword);
        }
        else{
            $items=(new itemmodel())->selectall();
        }
        //传入视图数据
        $this->assign('title','全部条目');
        $this->assign('keyword',$keyword);
        $this->assign('items',$items);

        //渲染试图
        $this->render();
    }

    //添加记录,测试myphp框架的sql查询-create
    public function add()
    {
        $data['item_name']=$_post['value'];
        $count=(new itemmodel)->add($data);

        $this->assign('title','添加成功');
        $this->assign('count',$count);

        //渲染试图
        $this->render();
    }

    //操作管理
    public function manage($id=null)
    {
        $item = array();
        $posturl=app_url.'/item/add';
        if($id)
        {
            $item=(new itemmodel)->select($id);
            $posturl=app_url.'/item/update';
        }

        $this->assign('title','管理条目');
        $this->assign('item',$item);
        $this->assign('posturl',$posturl);

        //渲染试图
        $this->render();
    }

    //更新记录,测试框架的sql查询-update
    public function update()
    {
        $data=array('id'=>$_post['id'],'item_name'=>$_post['value']);
        $count=(new itemmodel)->update($data['id'],$data);
        $this->assign('title','修改成功');
        $this->assign('count',$count);

        //渲染试图
        $this->render();
    }

    //删除记录,测试框架的sql查询-delete
    public function delete($id=null)
    {
        $count=(new itemmodel)->delete($id);
        $this->assign('title','删除成功');
        $this->assign('count',$count);

        //渲染试图
        $this->render();
    }
}

5.3 部署视图

在 application/views/目录下新建 header.php 和 footer.php 两个页头页脚模板文件,文件内容为:

header.php 内容:

<html>
<head>
    <meta http-equiv="content-type" content="text/html; charsert=utf-8"/>
    <title><?php echo $title; ?></title>
    <link rel="stylesheet" href="/static/css/main.css" type="text/css" />
</head>
<body>
<h1>
    <?php echo $title; ?>
</h1>

footer.php 内容:

</body>
</html>

页头文件使用了main.css文件,内容:

html,body{
    margin: 0;
    padding: 10px;
    font-size: 20px;
}

input{
    color:black;
    font-family: georgia, times;
    font-size:24px;
    font-weight:normal;
    line-height: 1.2em;
}

a{
    color:blue;
    font-family: georgia,times;
    font-size: 20px;
    font-weight: normal;
    line-height: 1.2em;
    text-decoration: none;
}

a:hover{
    text-decoration: underline;
}

h1{
    color: #000000;
    font-size: 41px;
    letter-spacing: -2px;
    line-height: 1em;
    font-family: helvetica,arial,sans-serif;
    border-bottom: 1px dotted #cccccc;
}

td{
    padding: 1px 30px 1px 0;
}

现在,在application/view/item/目录下,创建以下几个视图文件。

index.php,作用是展示数据库中item表的所有记录、检索记录、删除记录,文件内容为:

<form action="" method="get">
    <input type="text" value="<?php echo $keyword;?>" name="keyword">
    <input type="submit" value="搜索">
</form>

<p>
    <a href="<?php echo app_url; ?>item/manage">新建</a>
</p>

<table>
    <tr>
        <th>id</th>
        <th>内容</th>
        <th>操作</th>
    </tr>
    <?php foreach ($items as $item):?>
    <tr>
        <td><?php echo $item['id']; ?></td>
        <td><?php echo $item['item_name']; ?></td>
        <td>
            <a href="<?php echo app_url; ?>item/manage/<?php echo $item['id']; ?>">编辑</a>
            <a href="<?php echo app_url; ?>item/delete/<?php echo $item['id']; ?>">删除</a>
        </td>
    </tr>
    <?php endforeach;?>
</table>

manage.php,作用是编辑记录,文件内容为:

<form action="<?php echo $posturl; ?>" method="post">
    <?php if(isset($item['id'])): ?>
    <input type="hidden" name="id" value="<?php echo $item['id']; ?>">
    <?php endif; ?>
    <input type="text" name="value" value="<?php echo isset($item['item_name'])?$item['item_name']:''; ?>">
    <input type="submit" value="提交">
</form>

<a class="big" href="<?php echo app_url; ?>item/index">返回</a>

add.php,作用是提示 已添加记录,文件内容为:

<a class="big" href="<?php echo app_url; ?>item/index">
    成功添加<?php echo $count; ?>条记录,点击返回
</a>

update.php,作用是提示 已修改记录,文件内容为:

<a class="big" href="<?php echo app_url; ?>item/index">
    成功修改<?php echo $count; ?>项,点击返回
</a>

delete.php,作用是提示 已删除记录,文件内容为:

<a href="<?php echo app_url; ?>item/index">
    成功删除<?php echo $count; ?>项,点击返回
</a>

至此,所有的应用代码已经编写完成。

6、访问应用

在浏览器中访问 http://localhost/myphpframe1/  ,成功!

PHP MVC框架【Myphp】的编写

严重参考:

https://www.awaimai.com/128.html

https://www.cnblogs.com/steven-shi/p/5914175.html

感谢他们的分享!!