PHP学习笔记-MVC框架

2023-11-13

MVC学习笔记

1.什么使MVC框架

 

    MVC是一种软件开发框架,MVC将程序分为三个部分:模型层(M)、视图层(V)和控制层(C),对不同的层进行分层管理和控制,方便程序的修改和扩展

2. 为什么使用MVC框架

 

    在PHP中使用MVC框架,可以实现了分层、分类开发,实现了web的分离,使前端代码与后端分离,某一层的调整,不会对另一层的代码和逻辑造成影响,使用MVC开发框架更加方便程序的扩展,使开发的代码整体更加清晰

3.MVC的含义

 

    M(Model)模型层:提供了对数据库操作和链接的抽象层,主要完成大部分的业务逻辑和数据逻辑的处理

    V(view)视图层:主要负责处理结果的显示(渲染),用于与用户进行交互

    C(controller)控制层:根据请求进行相关的转发,调用相应的M(模型)对请求进行处理,并将请求结果返回给用户,决定结果的展示形式

 

    浏览器向服务器发起请求,首先由控制器将URL拦截,根据URL中的参数调用相应的模型层,模型层操作数据库,并将操作结果返回给Controller(控制层),控制层调用View层的相关代码对结果进行渲染,View层将渲染结果呈现给用户。

4. MVC目录结构

    项目根目录

    |-app层

    | |-controller

    | |-model

    | |-view

    |-config

 

5.重定向的作用:

    可以直接访问项目中的静态文件,除静态文件外,其他文件都有统一的程序入口,一般为index.php文件,如果使用nginx服务器则可以通过配置php.config中的重定向功能,是对应的字段重定向到指定路径下的指定入口文件,并将参数赋值给REQUEST_URI变量。PHP代码自身并不需要结束符号,不加结束符可以让程序更加安全,因为可以防止在程序的尾部注入

location / {   
     # 重新向所有非真是存在的请求到index.php    
    try_files $uri $uri/ /index.php$args;
}

6.入口文件

    主要分为两类,一类为项目的入口文件,规定程序访问时的统一入口;另一类是每一模块的入口文件,可以实现对模块的统一管理。入口文件主要实现程序的一些初始化设置,例如一些基础类、配置文件、数据库和模式等。例如:

    

<?php
    define('APP_PATH', __DIR__ . '/');// 应用目录为当前目录
    define('APP_DEBUG', true);// 开启调试模式
    require(APP_PATH . 'fastphp/Fastphp.php');// 加载框架文件
    $config = require(APP_PATH . 'config/config.php');// 加载配置文件
    (new fastphp\Fastphp($config))->run();// 实例化框架类通常为程序中的bootstrap.php文件

7.配置文件:

    配置文件分为两种,一种为程序的全局配置,例如数据库、默认控制器名和操作名等;另一种为局部配置,这种模块配置只有当访问到相关文件时,才会被对应的加载。全局的配置文件一般为命名为config.php内容如下:

<?php
    $config['db']['host'] = 'localhost';// 连接的数据库的域名
    $config['db']['username'] = 'root';//用户名
    $config['db']['password'] = '123456';//密码
    $config['db']['dbname'] = 'project';//使用的数据库名字

    $config['defaultController'] = 'Item';//控制器的名字
    $config['defaultAction'] = 'index';//通用才操作的名字
    return $config;

8.框架

    入口文件中调用了配置文件初始化了环境配置。定义了加载的控制器以及操作,所以在后续的调用中会根据配置文件的结果实例化框架的内容,实例化时会接受config中的相关参数(例如控制层、模型层和视图层),随后在入口文件中调用run函数进行相关的实例化。run函数的主要功能如下:

    1)类自动加载

    2)环境检查

    3)过滤敏感字符

    4)移除全局变量的老用法

    5)路由处理

代码:

<?phpnamespace fastphp;
    defined('CORE_PATH') or define('CORE_PATH', __DIR__);// 框架根目录
    class Fastphp{
        protected $config = [];// 配置内容
        public function __construct($config)
        {
            $this->config = $config;
        }
        public function run()
        {// 运行程序
            spl_autoload_register(array($this, 'loadClass'));
            $this->setReporting();
            $this->removeMagicQuotes();
            $this->unregisterGlobals();
            $this->setDbConfig();
            $this->route();
        }
    public function route()// 路由处理
    {
        $controllerName = $this->config['defaultController'];
        $actionName = $this->config['defaultAction'];
        $param = array();
        $url = $_SERVER['REQUEST_URI'];
        $position = strpos($url, '?');// 清除?之后的内容
        $url = $position === false ? $url : substr($url, 0, $position);
        $url = trim($url, '/');// 删除前后的“/”
        if ($url) {
            $urlArray = explode('/', $url);// 使用“/”分割字符串,并保存在数组中
            $urlArray = array_filter($urlArray);// 删除空的数组元素          
            $controllerName = ucfirst($urlArray[0]);// 获取控制器名
            
            array_shift($urlArray);// 获取动作名
            $actionName = $urlArray ? $urlArray[0] : $actionName;
            
            $array_shift($urlArray);// 获取URL参数
            $param = $urlArray ? $urlArray : array();
        }
        $controller = 'app\\controllers\\'. $controllerName . 'Controller';
	// 判断控制器和操作是否存在
        if (!class_exists($controller)) {
            exit($controller . '控制器不存在');
        }
        if (!method_exists($controller, $actionName)) {
            exit($actionName . '方法不存在');
        }
        // 如果控制器和操作名存在,则实例化控制器,
        $dispatch = new $controller($controllerName, $actionName);
        // $dispatch保存控制器实例化后的对象,我们就可以调用它的方法,
        call_user_func_array(array($dispatch, $actionName), $param);
    }
    public function setReporting()
    {// 检测开发环境
        if (APP_DEBUG === true) {
            error_reporting(E_ALL);
            ini_set('display_errors','On');
        } else {
            error_reporting(E_ALL);
            ini_set('display_errors','Off');
            ini_set('log_errors', 'On');
        }
    }
    public function stripSlashesDeep($value)
    {// 删除敏感字符
        $value = is_array($value) ? array_map(array($this, 'stripSlashesDeep'), $value) : stripslashes($value);
        return $value;
    }
    public function removeMagicQuotes()
    {// 检测敏感字符并删除
        if (get_magic_quotes_gpc()) {
            $_GET = isset($_GET) ? $this->stripSlashesDeep($_GET ) : '';
            $_POST = isset($_POST) ? $this->stripSlashesDeep($_POST ) : '';
            $_COOKIE = isset($_COOKIE) ? $this->stripSlashesDeep($_COOKIE) : '';
            $_SESSION = isset($_SESSION) ? $this->stripSlashesDeep($_SESSION) : '';
        }
    }
    // 检测自定义全局变量并移除。因为 register_globals 已经弃用,如果
    // 已经弃用的 register_globals 指令被设置为 on,那么局部变量也将
    // 在脚本的全局作用域中可用。 例如, $_POST['foo'] 也将以 $foo 的
    // 形式存在,这样写是不好的实现,会影响代码中的其他变量。 相关信息,
    // 参考: http://php.net/manual/zh/faq.using.php#faq.register-globals
    public function unregisterGlobals()
    {
        if (ini_get('register_globals')) {
            $array = array('_SESSION', '_POST', '_GET', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');
            foreach ($array as $value) {
                foreach ($GLOBALS[$value] as $key => $var) {
                    if ($var === $GLOBALS[$key]) {
                        unset($GLOBALS[$key]);
                    }
                }
            }
        }
    }
    public function setDbConfig()
    {// 配置数据库信息
        if ($this->config['db']) {
            define('DB_HOST', $this->config['db']['host']);
            define('DB_NAME', $this->config['db']['dbname']);
            define('DB_USER', $this->config['db']['username']);
            define('DB_PASS', $this->config['db']['password']);
        }
    }
    public function loadClass($className)
{// 自动加载类,可以设置为自动加载一个文件夹下的所以文件
        $classMap = $this->classMap();
        if (isset($classMap[$className])) {
            // 包含内核文件
            $file = $classMap[$className];
        } elseif (strpos($className, '\\') !== false) {
            // 包含应用(application目录)文件
            $file = APP_PATH . str_replace('\\', '/', $className) . '.php';
            if (!is_file($file)) {
                return;
            }
        } else {
            return;
        }
        include $file;    }
    protected function classMap()
    {// 内核文件命名空间映射关系
        return [
            'fastphp\base\Controller' => CORE_PATH . '/base/Controller.php',
            'fastphp\base\Model' => CORE_PATH . '/base/Model.php',
            'fastphp\base\View' => CORE_PATH . '/base/View.php',
            'fastphp\db\Db' => CORE_PATH . '/db/Db.php',
            'fastphp\db\Sql' => CORE_PATH . '/db/Sql.php',
        ];
    }
}

9.路由方法route():截取URL,并解析出控制器名、方法名和URL参数

    例如:https://my.csdn.net/?ref=toolbar当浏览器访问上面的URL,经过nginx的重写到指定的入口文件,并将参数ref=toolbar传递到调用的文件,route()从全局变量 $_SERVER['REQUEST_URI']中获取到字符串对应调取相应的控制器和方法。

10.基类    

    在框架中创建MVC基类,包括控制器模型视图三个基类,实现程序的调度。Controller 类用assign()方法实现把变量保存到View对象中。这样,在调用$this->render() 后视图文件就能显示这些变量。Model基类涉及到3个类:Model基类本身,它的父类SQL,以及提供数据库连接句柄的Db类。

<?php
namespace fastphp\base;
use fastphp\db\Sql;
class Model extends Sql{
    protected $model;
    public function __construct()
    {
        if (!$this->table) {// 获取数据库表名
            $this->model = get_class($this);// 获取模型类名称
            $this->model = substr($this->model, 0, -5);// 删除类名最后的 Model 字符
            $this->table = strtolower($this->model);// 数据库表名与类名一致
        }
    }
}
<?php
namespace fastphp\db;
use \PDOStatement;
class Sql{
    protected $table;// 数据库表名
    protected $primary = 'id';// 数据库主键
    private $filter = '';// WHERE和ORDER拼装后的条件
    private $param = array();// Pdo bindParam()绑定的参数集合
    public function where($where = array(), $param = array())
    {
        if ($where) {
            $this->filter .= ' WHERE ';
            $this->filter .= implode(' ', $where);
            $this->param = $param;
        }
        return $this;
    }
  public function order($order = array())
    {
        if($order) {
            $this->filter .= ' ORDER BY ';
            $this->filter .= implode(',', $order);
        }
        return $this;
    }
    public function fetchAll()// 查询所有
    {
        $sql = sprintf("select * from `%s` %s", $this->table, $this->filter);
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, $this->param);
        $sth->execute();
        return $sth->fetchAll();
    }
    public function fetch()// 查询一条
    {
        $sql = sprintf("select * from `%s` %s", $this->table, $this->filter);
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, $this->param);
        $sth->execute();
        return $sth->fetch();
    }
    public function delete($id)// 根据条件 (id) 删除
    {
        $sql = sprintf("delete from `%s` where `%s` = :%s", $this->table, $this->primary, $this->primary);
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, [$this->primary => $id]);
        $sth->execute();
        return $sth->rowCount();
    }
    public function add($data) // 新增数据
    {
        $sql = sprintf("insert into `%s` %s", $this->table, $this->formatInsert($data));
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, $data);
        $sth = $this->formatParam($sth, $this->param);
        $sth->execute();
       return $sth->rowCount();
    }
    public function update($data)// 修改数据
    {
        $sql = sprintf("update `%s` set %s %s", $this->table, $this->formatUpdate($data), $this->filter);
        $sth = Db::pdo()->prepare($sql);
        $sth = $this->formatParam($sth, $data);
        $sth = $this->formatParam($sth, $this->param);
        $sth->execute();
        return $sth->rowCount();
    }
    public function formatParam(PDOStatement $sth, $params = array())
    {
        foreach ($params as $param => &$value) {
            $param = is_int($param) ? $param + 1 : ':' . ltrim($param, ':');
            $sth->bindParam($param, $value);
        }
      return $sth;
    }
    private function formatInsert($data)
    {
        $fields = array();
        $names = array();
        foreach ($data as $key => $value) {
            $fields[] = sprintf("`%s`", $key);
            $names[] = sprintf(":%s", $key);
        }
        $field = implode(',', $fields);
        $name = implode(',', $names);
        return sprintf("(%s) values (%s)", $field, $name);
    }
    private function formatUpdate($data)
    {
        $fields = array();
        foreach ($data as $key => $value) {
            $fields[] = sprintf("`%s` = :%s", $key, $key);
        }
        return implode(',', $fields);
    }
}

    Sql类里面有用到Db:pdo()方法,这是我们创建的Db类,它提供一个PDO单例。在fastphp/db/目录下创建Db.php文件,内容:

<?php
namespace fastphp\db;
use PDO;use PDOException;
class Db{
    private static $pdo = null;
    public static function pdo()
    {
        if (self::$pdo !== null) {
            return self::$pdo;
        }
        try {
            $dsn    = sprintf('mysql:host=%s;dbname=%s;charset=utf8', DB_HOST, DB_NAME);
            $option = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
            return self::$pdo = new PDO($dsn, DB_USER, DB_PASS, $option);
        } catch (PDOException $e) {
            exit($e->getMessage());
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PHP学习笔记-MVC框架 的相关文章

随机推荐

  • 机器学习算法系列(二十一)-k近邻算法(k-Nearest Neighbor / kNN Algorithm)

    阅读本文需要的背景知识点 一丢丢编程知识 一 引言 前面一节我们学习了机器学习算法系列 二十 梯度提升决策树算法 Gradient Boosted Decision Trees GBDT 是一种集成学习的算法 这一节我们来学习一个相对简单直
  • Python 3.6打包成EXE可执行程序

    Python 3 6打包成EXE可执行程序 下载pyinstaller python 3 6 已经自己安装了pip 所以只需要执行 pip install pyinstaller就可以了 打包程序 进入到你你需要打包的目录 比如我在H xc
  • python爬虫工程师面经(2023年金三银四)

    python爬虫工程师面经 前言 面经总结 发展相关问题 爬虫基础相关问题 工作经验相关问题 总结 前言 过年期间 经过自我慎重的考虑后 终于决定在2月份向公司提出了辞职 说实话很慌 也做好了长时间找不到工作的准备 只是继续呆在公司对自我发
  • 用Kettle实现转换和作业例子

    一 转换 双击Kettle目录下的Spoon bat脚本 启动Kettle工具 在工具栏处选择 文件 新建 转换 命令 创建一个转换 名称默认是 转换1 选择 文件 保存 命令 可以对转换进行重命名以及选择转换保存路径 重命名为exampl
  • Java多线程-线程池ThreadPoolExecutor的submit返回值Future

    一般使用线程池执行任务都是调用的execute方法 这个方法定义在Executor接口中 public interface Executor void execute Runnable command 1 2 3 这个方法是没有返回值的 而
  • 微信企业号的基本配置流程(新手,勿喷!)

    一 登录微信公众号 确认登录的公众号为企业认证 二 打开开发里面的基本配置 如图 三 根据你的项目后台微信配置里面需要的数据 来在微信公众号的后台找到 然后 一一对应的写入你的项目后台的微信配置 如图 这是我的项目后台微信配置 四 按照自己
  • 《统计学习方法》学习笔记(一):概论

    统计学习方法三要素 模型 策略和算法 策略是想要最优解 模型给定输入 训练 得到输出 算法处理信息的方法 模型选择 正则化 交叉验证与学习泛化的能力 正则化 防止过拟合 简单来说是限制在规则之内 减小误差的行为 规则化 给需要训练的目标函数
  • Oracle的锁表与解锁

    Oracle的锁表与解锁 SELECT rule s username decode l type TM TABLE LOCK TX ROW LOCK NULL LOCK LEVEL o owner o object name o obje
  • Java学习:使用Freemarker导出简单的Word文档

    一 准备工作 准备想要导出的word文档的模板 准备maven的依赖
  • 实验室服务器conda使用教程

    目录 前言 1 下载conda 2 安装conda 3 检查conda是否安装成功 4 配置conda镜像 5 创建conda环境 6 在环境中安装模型所需的库文件 7 conda的其他用法 8 服务器离线安装python库文件 以torc
  • ubuntu下移植Qt软件

    export PATH home ubuntu yhj plugins PATH export QTDIR home ubuntu yhj plugins export LD LIBRARY PATH QTDIR lib LD LIBRAR
  • Kvrocks 在 RocksDB 上的优化实践

    不久前 Kvrocks 发布 2 0 5 版本 该版本不仅增加了许多新功能 还使用了RocksDB 的新特性大大提升了性能 本文将重点介绍 Kvrocks 是如何使用这些特性来提升磁盘类型 Redis 服务的性能 希望能给大家带来一些参考
  • mock.js文档详解1及下载(数据模板)

    作用 生成随机数据 拦截Ajax请求 mock数据模板的书写规则 属性名 规则 属性值 规则共有七种 1 name min max value 针对value的不同类型会有不同意义 2 name count value 3 name min
  • 手机按键失灵怎么修复_手机触摸屏失灵了怎么办,六种方法自己就能修好它!...

    你是否碰到这种抓狂的时候 手机屏幕总是要按多几下才能反应过来 有时点了好几下也依然没反应 其实 发生这样的触屏失灵的问题 也是有多方面的原因造成 有时是外在的客观原因引起 有时是个人的主观因素导致 如今 我们的手机绝大多数都是电容屏的 而电
  • 2022全国高校计算机能力挑战赛决赛python组编程计挑赛决赛3

    输入格式 一个日期 格式 年 月 日 1 算法中要能够自动对输入的日期进行判断 若年份不是2022年或月份不是1月份至8月份中的某一个月份值 则输出 数据输入错误 2 算法中能够对输入的 日 的数字进行判断 要按照实际情况进行判断 如1 3
  • ChatGLM2-6B! 我跑通啦!本地部署+微调(windows系统)

    ChatGLM2 6B 我跑通啦 windows系统 1 跑通了啥 2 咋跑通的 2 1 ChatGLM2 6B本地部署 2 2 ChatGLM2 6B本地微调 2 3 小结 3 打算做什么 1 跑通了啥 记录一下此时此刻 2023年7月8
  • pythonSDK安装+Visual Studio Code

    安装PythonSDK 点击去下载python的SDK https www python org 去下载 双击 下载好的安装包 等待安装可能会很慢 如何验证是否成功安装了python的SDK Windows电脑 打开 CMD 窗口 如何打开
  • iOS开发之动画篇-基础篇1

    基础篇 一 制作动画的原理 十二个基本的动画原理 网页动画的十二原则 参考全部开源的HTML和CSS代码实现 二 寻找灵感 1 知名设计师共享平台 Dribbble相当于程序员的gitHub 2 pttrns 手机设计较多 三 制作动画的基
  • 2019零基础如何学好Python?学习Python的策略是什么?

    跟几个IT界的大佬提起python 他们说零基础学好python很简单 python进阶需要花费写气力 都说Python简单易学 那么零基础如何学好Python 有哪些必须学的知识 学习的策略技巧有哪些 今天这篇文章将会给你启发 Pytho
  • PHP学习笔记-MVC框架

    MVC学习笔记 1 什么使MVC框架 MVC是一种软件开发框架 MVC将程序分为三个部分 模型层 M 视图层 V 和控制层 C 对不同的层进行分层管理和控制 方便程序的修改和扩展 2 为什么使用MVC框架 在PHP中使用MVC框架 可以实现