手把手编写自己的PHP MVC框架实例教程

PHP 64207浏览 153评论

1 什么是MVC

MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式

MVC把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

PHP中MVC模式也称Web MVC,从上世纪70年代进化而来。

MVC的目的是实现一种动态的程序设计,便于后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。

除此之外,此模式通过对复杂度的简化,使程序结构更加直观。

MVC各部分的职能:

  • 模型Model – 管理大部分的业务逻辑所有的数据库逻辑。模型提供了连接和操作数据库的抽象层。
  • 控制器Controller - 负责响应用户请求准备数据,以及决定如何展示数据。
  • 视图View – 负责渲染数据,通过HTML方式呈现给用户。

MVC流程图

一个典型的Web MVC流程:

  1. Controller截获用户发出的请求;
  2. Controller调用Model完成状态的读写操作;
  3. Controller把数据传递给View;
  4. View渲染最终结果并呈献给用户。

2 为什么要自己开发MVC框架

网络上有大量优秀的MVC框架可供使用,本教程并不是为了开发一个全面的、终极的MVC框架解决方案。

我们将它看作是一个很好的从内部学习PHP的机会。

在此过程中,你将学习面向对象编程MVC设计模式,并学习到开发中的一些注意事项。

更重要的是,通过自制MVC框架,每个人都可以完全控制自己的框架,将你的想法融入到你开发的框架中。

虽然不一定是最好的,但是你可以按照自己的方式开发各种功能。

3 开始开发自己的MVC框架

3.1 目录准备

在开始开发前,让我们先来把项目建立好。

假设我们建立的项目为 project,MVC的框架命名为 fastphp,那么接下来,第一步要把目录结构设置好。

project  WEB部署目录
├─application           应用目录
│  ├─controllers        控制器目录
│  ├─models             模块目录
│  ├─views              视图目录
├─config                配置文件目录
├─fastphp               框架核心目录
├─static                静态文件目录
├─index.php             入口文件

然后把Nginx或者Apache的站点根目录配置到project目录。

3.2 代码规范

在目录设置好以后,我们接下来规定代码的规范:

  1. MySQL的表名需小写小写加下划线,如:itemcar_orders
  2. 模块名(Models)需用大驼峰命名法,即首字母大写,并在名称后添加Model,如:ItemModelCarModel
  3. 控制器(Controllers)需用大驼峰命名法,即首字母大写,并在名称后添加Controller,如:ItemControllerCarController
  4. 方法名(Action)需用小驼峰命名法,即首字母小写,如:indexindexPost
  5. 视图(Views)部署结构为控制器名/行为名,如:item/view.phpcar/buy.php

上述规则是为了程序能更好地相互调用。

接下来就开始真正的PHP MVC编程了。

3.3 重定向

重定向的目的有两个:设置根目录为project所在位置,以及将所有请求都发送给 index.php 文件。

如果是Apache服务器,在 project 目录下新建一个 .htaccess 文件,内容为:

<IfModule mod_rewrite.c>
    # 打开Rerite功能
    RewriteEngine On

    # 如果请求的是真实存在的文件或目录,直接访问
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    # 如果访问的文件或目录不是真事存在,分发请求至 index.php
    RewriteRule . index.php
</IfModule>
如果是Nginx服务器,修改配置文件,在server块中加入如下的重定向:
location / {
    # 重新向所有非真是存在的请求到index.php
    try_files $uri $uri/ /index.php$args;
}
这样做的主要原因是:

(1)静态文件能直接访问。

如果文件或者目录真实存在,则直接访问存在的文件/目录。

比如,静态文件static/css/main.css真实存在,就可以直接访问它。

(2)程序有单一的入口

这种情况是请求地址不是真实存在的文件或目录,这样请求就会传到 index.php 上。

例如,访问地址:localhost/item/view/1,在文件系统中并不存在这样的文件或目录。

那么,Apache或Nginx服务器会把请求发给index.php,并且把域名之后的字符串赋值给REQUEST_URI变量。

这样在PHP中用$_SERVER['REQUEST_URI']就能拿到/item/view/1

(3)可以用来生成美化的URL,利于SEO

3.4 入口文件

接下来,在 project 目录下新建 index.php 入口文件,文件内容为:

<?php
// 应用目录为当前目录
define('APP_PATH', __DIR__ . '/');

// 开启调试模式
define('APP_DEBUG', true);

// 加载框架文件
require(APP_PATH . 'fastphp/Fastphp.php');

// 加载配置文件
$config = require(APP_PATH . 'config/config.php');

// 实例化框架类
(new Fastphp($config))->run();
注意,上面的PHP代码中,并没有添加PHP结束符号?>
这么做的主要原因是:
对于只有 PHP 代码的文件,最好没有结束标志?>
PHP自身并不需要结束符号,不加结束符让程序更加安全,很大程度防止了末尾被注入额外的内容。

3.5 配置文件

在入口文件中,我们加载了config.php文件的内容,那它有何作用呢?

从名称不难看出,它的作用是保存一些常用配置

config.php 文件内容如下,作用是定义数据库连接参数参数,以及配置默认控制器名和操作名:

<?php

// 数据库配置
define('DB_NAME', 'project');
define('DB_USER', 'root');
define('DB_PASSWORD', '123456');
define('DB_HOST', 'localhost');

// 默认控制器和操作名
$config['defaultController'] = 'Item';
$config['defaultAction'] = 'index';

return $config;

入口中的$config变量接收到配置参数后,再传给框架的核心类,也就是Fastphp类。

 

3.6 框架核心类

入口文件对框架类做了两步操作:实例化调用run()方法
实例化操作接受$config参数配置,并保存到类属性中。
run()方法则调用用类自身方法,完成:自动加载类文件、监测开发环境、过滤敏感字符、移除全局变量的老用法、和处理路由
<?php
/**
 * fastphp框架核心
 */
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;
            
            // 获取URL参数
            array_shift($urlArray);
            $param = $urlArray ? $urlArray : array();
        }

        // 判断控制器和操作是否存在
        $controller = $controllerName . 'Controller';
        if (!class_exists($controller)) {
            exit($controller . '控制器不存在');
        }
        if (!method_exists($controller, $actionName)) {
            exit($actionName . '方法不存在');
        }

        // 如果控制器和操作名存在,则实例化控制器,因为控制器对象里面
        // 还会用到控制器名和操作名,所以实例化的时候把他们俩的名称也
        // 传进去。结合Controller基类一起看
        $dispatch = new $controller($controllerName, $actionName);

        // $dispatch保存控制器实例化后的对象,我们就可以调用它的方法,
        // 也可以像方法中传入参数,以下等同于:$dispatch->$actionName($param)
        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']) {
            Model::$dbConfig = $this->_config['db'];
        }
    }

    // 自动加载控制器和模型类 
    public static function loadClass($class)
    {
        $frameworks = __DIR__ . '/' . $class . '.php';
        $controllers = APP_PATH . 'application/controllers/' . $class . '.php';
        $models = APP_PATH . 'application/models/' . $class . '.php';

        if (file_exists($frameworks)) {
            // 加载框架核心类
            include $frameworks;
        } elseif (file_exists($controllers)) {
            // 加载应用控制器类
            include $controllers;
        } elseif (file_exists($models)) {
            //加载应用模型类
            include $models;
        } else {
            // 错误代码
        }
    }
}

下面重点讲解主请求方法 route(),它也称路由方法,作用是:截取URL,并解析出控制器名、方法名和URL参数

假设我们的 URL 是这样:

yoursite.com/controllerName/actionName/queryString

当浏览器访问上面的URL,route()从全局变量 $_SERVER['REQUEST_URI']中获取到字符串/controllerName/actionName/queryString

然后,会将这个字符串分割成三部分:controlleractionqueryString

例如,URL链接为:yoursite.com/item/view/1/hello,那么route()分割之后,

  • Controller名就是:item
  • action名就是:view
  • URL参数就是:array(1, hello)

分割完成后,再实例化控制器:itemController,并调用其中的view方法 。

3.7 Controller基类

接下来,就是在 fastphp 中创建MVC基类,包括控制器模型视图三个基类。

新建控制器基类,文件名 Controller.class.php,功能就是总调度,内容如下:

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

    // 分配变量
    public function assign($name, $value)
    {
        $this->_view->assign($name, $value);
    }

    // 渲染视图
    public function render()
    {
        $this->_view->render();
    }
}

Controller 类用assign()方法实现把变量保存到View对象中

这样,在调用$this-> render() 后视图文件就能显示这些变量。

3.8 Model基类

新建模型基类,继承自数据库操作类Sql类(因为数据库操作比较复杂)。

模型基类文件名为 Model.class.php,代码如下:

<?php

class Model extends Sql
{
    protected $_model;
    protected $_table;
    public static $dbConfig = [];

    public function __construct()
    {
        // 连接数据库
        $this->connect(self::$dbConfig['host'], self::$dbConfig['username'], self::$dbConfig['password'],
            self::$dbConfig['dbname']);

        // 获取数据库表名
        if (!$this->_table) {
            // 获取模型类名称
            $this->_model = get_class($this);
            // 删除类名最后的 Model 字符
            $this->_model = substr($this->_model, 0, -5);

            // 数据库表名与类名一致
            $this->_table = strtolower($this->_model);
        }
    }
}

建立一个数据库基类 Sql.class.php,代码如下:

<?php 

class Sql
{
    protected $_dbHandle;
    protected $_result;
    private $filter = '';

    // 连接数据库
    public function connect($host, $username, $password, $dbname)
    {
        try {
            $dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8", $host, $dbname);
            $option = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
            $this->_dbHandle = new PDO($dsn, $username, $password, $option);
        } catch (PDOException $e) {
            exit('错误: ' . $e->getMessage());
        }
    }

    // 查询条件
    public function where($where = array())
    {
        if (isset($where)) {
            $this->filter .= ' WHERE ';
            $this->filter .= implode(' ', $where);
        }

        return $this;
    }

    // 排序条件
    public function order($order = array())
    {
        if(isset($order)) {
            $this->filter .= ' ORDER BY ';
            $this->filter .= implode(',', $order);
        }

        return $this;
    }

    // 查询所有
    public function selectAll()
    {
        $sql = sprintf("select * from `%s` %s", $this->_table, $this->filter);
        $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($sql);
        $sth->execute();

        return $sth->rowCount();
    }

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

        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);
    }

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

        $field = implode(',', $fields);
        $value = implode(',', $values);

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

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

        return implode(',', $fields);
    }
}

应该说,Sql.class.php 是框架的核心部分。为什么?

因为通过它,我们创建了一个 SQL 抽象层,可以大大减少了数据库的编程工作。

虽然 PDO 接口本来已经很简洁,但是抽象之后框架的可灵活性更高。

这里的数据库句柄$this->_dbHandle还能用单例模式返回,让数据读写更高效,这部分可自行实现。

3.9 View基类

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

<?php
/**
 * 视图基类
 */
class View
{
    protected $variables = array();
    protected $_controller;
    protected $_action;

    function __construct($controller, $action)
    {
        $this->_controller = strtolower($controller);
        $this->_action = strtolower($action);
    }
 
    // 分配变量
    public function assign($name, $value)
    {
        $this->variables[$name] = $value;
    }
 
    // 渲染显示
    public function render()
    {
        extract($this->variables);
        $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';
        $controllerLayout = APP_PATH . 'application/views/' . $this->_controller . '/' . $this->_action . '.php';

        // 页头文件
        if (file_exists($controllerHeader)) {
            include ($controllerHeader);
        } else {
            include ($defaultHeader);
        }

        include ($controllerLayout);
        
        // 页脚文件
        if (file_exists($controllerFooter)) {
            include ($controllerFooter);
        } else {
            include ($defaultFooter);
        }
    }
}

这样,核心的PHP MVC框架核心就完成了。

下面我们编写应用来测试框架功能。

4 应用

4.1 数据库部署

在 SQL 中新建一个 project 数据库,增加一个item 表、并插入两条记录,命令如下:

CREATE DATABASE `project` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `project`;

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, 'Lets go!');

4.2 部署模型

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

<?php

/**
 * 用户Model
 */
class ItemModel extends Model
{
    /**
     * 自定义当前模型操作的数据库表名称,
     * 如果不指定默认为类名称的小写字符串,
     * 这里就是 item 表
     * @var string
     */
    public $_table = 'item';

    /**
     * 搜索功能,因为Sql父类里面没有现成的like搜索,
     * 所以需要自己写SQL语句,对数据库的操作应该都放
     * 在Model里面,然后提供给Controller直接调用
     * @param $title string 查询的关键词
     * @return array 返回的数据
     */
    public function search($keyword)
    {
        $sql = "select * from `$this->_table` where `item_name` like '%$keyword%'";
        $sth = $this->_dbHandle->prepare($sql);
        $sth->execute();

        return $sth->fetchAll();
    }
}

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

4.3 部署控制器

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

<?php
 
class ItemController extends Controller
{
    // 首页方法,测试框架自定义DB查询
    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();
    }
    
    // 添加记录,测试框架DB记录创建(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 = 0)
    {
        $item = array();
        $postUrl = '/item/add';
        if ($id) {
            $item = (new ItemModel)->select($id);
            $postUrl = '/item/update';
        }

        $this->assign('title', '管理条目');
        $this->assign('item', $item);
        $this->assign('postUrl', $postUrl);
        $this->render();
    }
    
    // 更新记录,测试框架DB记录更新(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();
    }
    
    // 删除记录,测试框架DB记录删除(Delete)
    public function delete($id = null)
    {
        $count = (new ItemModel)->delete($id);

        $this->assign('title', '删除成功');
        $this->assign('count', $count);
        $this->render();
    }
}

4.4 部署视图

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

header.php 内容:

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=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 {
    font-family:georgia,times;
    font-size:24px;
    line-height:1.2em;
}

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

a:hover {
    text-decoration:underline;
}

h1 {
    color:#000000;
    font-size:41px;
    border-bottom:1px dotted #cccccc;
}

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

然后,在 views/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="/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="/item/manage/<?php echo $item['id'] ?>">编辑</a>
                <a href="/item/delete/<?php echo $item['id'] ?>">删除</a>
            </td>
        </tr>
    <?php endforeach ?>
</table>

add.php,添加记录后的提示,内容:

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

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="/item/index">返回</a>

update.php,更改记录后的提示,内容:

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

delete.php,删除记录后的提示,内容:

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

4.5 应用测试

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

result

以上代码已经全部发布到 github 上,关键部分加了注释:

要设计更好的MVC,或使用得更加规范,请看《MVC架构的职责划分原则》。

 

内容不错?

我要小额赞助,鼓励作者

 

参考资料:

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (153)

  1. 运营报错了。 Warning: mysql_num_fields() expects parameter 1 to be resource, boolean given in D:\phpStudy\WWW\fast\fastphp\Sql.class.php on line 60 Warning: mysql_fetch_row() expects parameter 1 to be resource, boolean given in D:\phpStudy\WWW\fast\fastphp\Sql.class.php on line 66 Warning: mysql_result() expects at least 2 parameters, 1 given in D:\phpStudy\WWW\fast\fastphp\Sql.class.php on line 72
    D.Deng 1年前 (2016-04-18) 回复 编辑
    • 应该是数据库连接不上导致的,把 $this->_dbHandle = @mysql_connect($address, $account, $pwd); 这一句中的 @ 去掉,可以显示具体错误。
      歪麦 1年前 (2016-04-21) 回复 编辑
  2. 怒赞
    刘sir 1年前 (2016-04-26) 回复 编辑
  3. 不错,很原始的设计。
    fatrbaby 1年前 (2016-04-27) 回复 编辑
  4. 为啥不用composer
    Awezome 1年前 (2016-06-05) 回复 编辑
    • 目前只仅为了说明原理,用composer就复杂了。以后完善了再composer
      歪麦 1年前 (2016-06-12) 回复 编辑
  5. 你好 教程写的很好,是我看过最良心的MVC框架介绍了,请问是否有兴趣继续把这个框架写下去,建议把mysql用mysqli,然后加一下路由,可以一步步慢慢扩展开来。还有文章里有个问题就是,你建的table有错误,itmes该为item就可以正常使用了,上面那位兄弟就是这个原因。
    steve 1年前 (2016-06-09) 回复 编辑
    • 非常感谢你的建议,我们会每隔一段时间优化这个框架,谢谢!
      歪麦 1年前 (2016-06-11) 回复 编辑
      • model 中怎么调用操作sql的方法 😀
        kimen 2周前 (06-22) 回复 编辑
        • 因为model继承了Sql类,所以直接用$this调用,例如:
          $this->selectAll();
          
          歪麦 2周前 (06-22) 回复 编辑
  6. 写的很不错
    我是东方的旭日 1年前 (2016-06-23) 回复 编辑
  7. 我看了你的框架 很适合用在中小型 的 网站 上手快速 只是里面我有更改了一些东西 除了 MVC 之外 我有加入一个Helper 的基类 然后延伸Pagination / Upload / Validation 那些逻辑 这个类 主旨是能够重用 还有加入了 不同用户的权限 限制 例如User 只能用到 User的 controller 我对你的框架很有兴趣 如果可以的话 请email我 讨论一起发展下去?
    Jacky 1年前 (2016-07-10) 回复 编辑
  8. 之前的 $_GET =stripSlashesDeep($_GET );我改成了 $_GET =$this->stripSlashesDeep($_GET );不然会报错,是不是我php版本造成的,我是一个新手。不太懂这个,然后访问根目录有报如下错误。 Fatal error: Class 'IndexController' not found in E:\apmserv\APMServ-v5.2.6\APMServ5.2.6\www\htdocs\fastphp\fastphp\Core.php on line 47 请问这个是什么原因造成的?
    gsl 12个月前 (07-14) 回复 编辑
    • 如果用 PHP5.2.6,就会有这个问题的,请使用 PHP5.4.0+ 。如果测试环境是Windows,可使用 phpStudy 来搭建环境,能切换多个版本的PHP。
      歪麦 12个月前 (07-17) 回复 编辑
      • PHP 7.0.6 也出現這個 是一個原因嗎?
        ckc 10个月前 (09-24) 回复 编辑
        • 请问具体的提示是怎样的呢?
          歪麦 10个月前 (09-24) 回复 编辑
  9. 使用php5.4,测试成功。很需要这种简单的原生的mvc,用于简化学习。非常感谢!
    mvcer 11个月前 (08-08) 回复 编辑
  10. 你好,最近在写基于MVC的php框架的论文,看了你写的对我有很大的帮助,在此表示感谢。如果加上一些思想的讲解,比如模型层引用的PDO等等。
    美丽心情 11个月前 (08-19) 回复 编辑
  11. 谢谢 不错的教程.易懂适合我这样的菜鸟学习。 😆
    乌班图 10个月前 (09-04) 回复 编辑
  12. 首先谢谢博主的分享,让我学到了很多东西、我现在不解的是 ,(URL链接为:project.com/item/view/1/first-item $controller 就是:item $action 就是:view)是在哪个部分执行到了 index.php 为什么不用写project.com/index.php/item/view/1/first-item 就能引用到框架类库
    凯旋 9个月前 (10-12) 回复 编辑
    • 在.htaccess文件中有这么一行:
      RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
      作用是重定向请求到:index.php?url=。 例如:当我们请求<域名>item/index时,实际上是请求<域名>index.php?url=item/index。在PHP中用 GET['url'] 就能拿到字符串item/index,请看Core.php中的Route()方法。
      歪麦 9个月前 (10-14) 回复 编辑
      • 明白啦 谢谢博主 😈
        凯旋 9个月前 (10-15) 回复 编辑
      • 博主你好!这个$_GET['url']我查了好多资料,还是没搞清楚是什么意思。这个url参数是php本身就有的,还是您在哪里定义的?
        zhou 8个月前 (11-05) 回复 编辑
        • 文件.htaccess中有这样一句:
          RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
          
          例如,当访问了:www.awaimai.com/a/b,传到PHP获得的地址就是:www.awaimai.com/index.php?url=a/b,用$_GET['url']就能得到字符串a/b
          歪麦 8个月前 (11-05) 回复 编辑
          • 明白了 谢谢博主!
            zhou 8个月前 (11-06) 编辑
  13. 博主你好 我是初学者 我看了你的框架 感觉帮助很大 谢谢
    9个月前 (10-17) 回复 编辑
    • 非常荣幸能够帮上忙 ,欢迎多多光顾:)
      歪麦 9个月前 (10-17) 回复 编辑
  14. 我的数据库是MSSQL,配置文件要怎么改
    speclalized-呆萌 9个月前 (10-20) 回复 编辑
    • MSSSQL需要修改Sql.class.php文件中的PDO连接,如下一行:
      $dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8", $host, $dbname);
      改成MSSQL连接方式。
      歪麦 9个月前 (10-20) 回复 编辑
  15. Notice: Undefined variable: items in E:\Apache\htdocs\project\application\views\item\index.php on line 9 Warning: Invalid argument supplied for foreach() in E:\Apache\htdocs\project\application\views\item\index.php on line 9 报错额,
    specialized-呆萌 9个月前 (10-21) 回复 编辑
    • 说明没读出数据库里面的数据,需要调整Sql.class.php中点fetchaAll()等方法。 建议先用MySQL调通之后再换MSSQL。
      歪麦 9个月前 (10-21) 回复 编辑
      • 我换成mysql,还是这错误
        specialized-呆萌 9个月前 (10-21) 回复 编辑
  16. 我在用你框架的时候出现了控制器找不到的错误,怎么解决呢?
    zd 9个月前 (10-21) 回复 编辑
    • 用的github的代码么?可否把错误贴出来呢?
      歪麦 9个月前 (10-21) 回复 编辑
      • Fatal error: Class 'ItemController' not found in E:\web\WWW\mvc\fastphp\Core.php on line 45 是这样的,我把你的代码从网站上复制下去,打开就是这样,能够告诉我是哪里出问题了吗?
        zd 9个月前 (10-21) 回复 编辑
        • 建议直接从github上clone一份
          歪麦 9个月前 (10-23) 回复 编辑
        • 可能是大小写的问题
          AMOR 9个月前 (10-23) 回复 编辑
  17. 少了个路由,希望这个能加上去,还有少了个加载自定义类库的方法.
    ant 9个月前 (10-22) 回复 编辑
    • 嗯,感谢提议!目前在Core.php文件的route()方法中,有做简单点路由处理呢 🙂
      歪麦 9个月前 (10-22) 回复 编辑
  18. 博主可以问一下吗?ItemController里面没有调用方法给 content赋值,为什么可以显示view 里面相应的content内容呢?比如 views/item/index.php 、add.php
    AMOR 9个月前 (10-23) 回复 编辑
    • 在View基类中,有两个方法:assign()render()assign()将变量保存到variables数组中,render()输出变量,在之后用include包含方式显示。
      歪麦 9个月前 (10-23) 回复 编辑
      • 你好,可以问个问题么。$dispatch = new $controller($controllerName, $action);里面的$controllerName, $action是怎么传过来的
        一世宁安 8个月前 (11-06) 回复 编辑
        • 通过URL传递过来的。
          歪麦 8个月前 (11-08) 回复 编辑
      • 为什么的的评论一直显示排队审核中。。。
        一世宁安 8个月前 (11-07) 回复 编辑
  19. 楼主楼主,这个情况该怎么解决, /home/u980175229/public_html/ 是我的php空间的目录, php版本 5.5 Fatal error: Class 'IndexController' not found in /home/u980175229/public_html/fastphp/Core.php on line 45
    victcity 8个月前 (11-10) 回复 编辑
    • 应该是复制代码有缺失导致的,建议直接通过github克隆代码。
      歪麦 8个月前 (11-11) 回复 编辑
  20. 连接oracle 所有sql语句都要改
    agoni 7个月前 (11-25) 回复 编辑
    • 只需要改Sql类就可以了。
      歪麦 7个月前 (11-26) 回复 编辑
  21. 博主你好,我是一个初入门的PHP新手,之前学习了PHP的基础知识,然后又学习了一些网站项目的功能实现,都比较简单.这是第一次接触到MVC这个概念,按照您的教程做,发现绝大多数代码都不懂其含义,也出现了很多即便是查资料也一知半解的函数.我本来想针对于几个特别难懂的点问您,后来发现不懂的太多了,没可能一个一个问,所以想请问您,有什么更好的方式能使我这种新手更有助于理解的方法吗? 一些其他的相关知识? 书籍? 我想也许是我的基础知识底蕴还不够,可是我不知道涉及到这篇文章需要了解哪些知识,总之,希望能获得您的帮助,感激不尽!
    noob 7个月前 (12-01) 回复 编辑
  22. 请问一下: public function add() { $val = !empty($_POST["value"]) ? $_POST["value"] : "没有获取到文本值"; $data['item_name'] =$val; 为什么$_POST["value"] 获取不到值呢?
    marshal 7个月前 (12-12) 回复 编辑
    • 检查一下PHP环境。
      歪麦 7个月前 (12-12) 回复 编辑
  23. // 添加记录,测试框架DB记录创建(Create) public function add() { var_dump($_POST);die; $val = !empty($_POST["value"]) ? $_POST["value"] : "没有获取到文本值"; 是个空数组,这是什么问题呢?
    marshal 7个月前 (12-12) 回复 编辑
    • 检查一下PHP环境,代码测试过OK。
      歪麦 7个月前 (12-12) 回复 编辑
  24. 博主你好,非常感谢你的分享,我这里有个问题,你在Core.php文件中的route路由处理方法中,有那么以下两句: // 实例化控制器 $controller = $controllerName . 'Controller'; $dispatch = new $controller($controllerName, $action); 我想问一下,$dispatch = new $controller($controllerName, $action);这一句代码,我看你好像也没有引进什么文件啊,这样实例化类会报错吧,而且我运行的时候也报错了:Fatal error: Class 'ItemController' not found in F:\wwwroot\myframe\fastphp\Core.php on line 44
    Apollo 7个月前 (12-12) 回复 编辑
    • 不需要手动include的,用spl_autoload_register(array($this, 'loadClass'));就可以实现通过loadClass()方法自动加载类文件。 如果报错,请确认PHP为5.4+版本,建议从github下载最新的代码。
      歪麦 7个月前 (12-12) 回复 编辑
      • 嗯嗯,刚刚走了一遍这个代码,基本上可以理解了。非常感谢
        Apollo 7个月前 (12-12) 回复 编辑
    • 我知道了,那个控制器的文件名应该为ItemController.class.php,而不是ItemController.php
      Apollo 7个月前 (12-12) 回复 编辑
  25. 您好!歪麦,我是从phpchina获得此教程,然后过来学习的,近期有意向自己写程序,搞个轻论坛,但鉴于现时的轻论坛项目过于同质化,某些RUBY些的,或者基于laravel框架的一些程序,对我来说又难以部署和维护,所以想零基础学习PHP+MYSQL,结合一些前端框架,比如BOOTSTRAPE,编写一套功能相对简单,但完全符合自己期望的轻论坛,现在经您介绍,对于MVC架构的开发工作有了较详细的了解,但对于字符的入库和出库处理,还是比较朦胧,不知您是否有空闲可以略作介绍?如果可以,真是非常感激。再次感谢你的教程,这对初学者帮助非常大!
    kimwang 6个月前 (12-25) 回复 编辑
    • 字符的入库和出库是否指的是数据库的增查改删(CRUD)? 这个在我们的框架中也有的哟,就是Sql类,增查改删都有的,用的是PDO类来读写数据库。 如果不理解,可以详细看看PHP网站PDO的介绍。
      歪麦 6个月前 (12-26) 回复 编辑
      • 你好,可能是我表述得不够好,我想请教的可能是关于转义方面的问题?在具体一点,假如现在我要开发一个轻论坛,那么用户发帖时的内容里面,如果含有换行、空格、甚至HTML标记、代码等,我应该如何对危害数据库/程序安全的字符过滤?如何对换行、空格等正常入库,而查的时候又能正常恢复其原有行为格式?歪麦可以给点思路吗,谢谢。
        kimwang 6个月前 (12-26) 回复 编辑
        • 使用PDO的预处理语句就可以基本解决:http://php.net/manual/zh/pdo.prepared-statements.php PHP网站也对SQL注入有介绍:http://php.net/manual/zh/security.database.sql-injection.php
          歪麦 6个月前 (01-03) 回复 编辑
          • 收到,谢谢你!
            kimwang 6个月前 (01-09) 编辑
  26. 很不错的PHP文章,从头开始设计PHP框架。
    PHP程序员雷雪松 6个月前 (12-28) 回复 编辑
  27. 博主,请问fashphp目录下的那些类怎么引进去的啊?比如sql.class.php等
    学生 6个月前 (01-03) 回复 编辑
    • loadClass方法实现类加载,再用PHP的spl_autoload_register方法自动加载
      歪麦 6个月前 (01-03) 回复 编辑
  28. 请教博主, 检测自定义全局变量(register globals)并移除,这段代码的具体作用是什么,可以举个例子吗?谢啦
    学生 6个月前 (01-04) 回复 编辑
    • 因为 register_globals 已经弃用。 如果已经弃用的 register_globals 指令被设置为 on,那么局部变量也将在脚本的全局作用域中可用。 例如, $_POST['foo'] 也将以 $foo 的形式存在,这样写是不好的实现,会影响代码中的其他变量。 相关信息,参见 FAQ “register_globals 对我有什么影响?
      歪麦 6个月前 (01-04) 回复 编辑
  29. 这哪里是参考!! 完全就是翻译!!!!!
    1111 6个月前 (01-09) 回复 编辑
  30. 😀
    啊啊啊 5个月前 (02-10) 回复 编辑
  31. Controller类中初始化里有下面的一条语句 $this->_view = new View($controller, $action); 哪个地方包含了View.class.php文件?之前没有系统说过php,房主解答下。
    ourenyou 4个月前 (02-28) 回复 编辑
  32. php 5.4+ 版本的,你的框架好像没有对特殊符号转义呢
    GD 4个月前 (03-02) 回复 编辑
    • 各种数据都有自己不同的用途,在入口对数据一刀切地进行转义,这种方式并不优雅,还有可能带来不必要的麻烦。 所以PHP5.4+取消了这个功能。 详情可看PHP官网解释:http://php.net/manual/en/security.magicquotes.php
      歪麦 4个月前 (03-05) 回复 编辑
  33. 缺陷是一个model不能调用其他model
    aa 4个月前 (03-04) 回复 编辑
  34. 请问博主nginx服务器怎么配置 .htaccess 文件呢?
    kavi 4个月前 (03-10) 回复 编辑
  35. public function where($where = array())请问这个方法是用来干麻的?看不懂
    kavi 4个月前 (03-16) 回复 编辑
    • 拼装MySQL的WHERE条件
      歪麦 4个月前 (03-17) 回复 编辑
  36. 博主,有没有 Model 传递记录给 Control 的Demo?一次性传递多条数据的
    He110 4个月前 (03-22) 回复 编辑
    • 额。。。不太明白,能否详细描述详细一点呢
      歪麦 4个月前 (03-22) 回复 编辑
  37. 楼主请教下, autoload 自动加载里 用 require require_once include include_once 有什么区别么?网上看大家各种写法都有。找资料找半天也没找到
    一颗星 3个月前 (03-29) 回复 编辑
    • 这几个函数是有区别的,require遇到警告时更严厉,include则比较宽松。具体请看另一篇文章:PHP函数include include_once require和require_once的区别
      歪麦 3个月前 (03-30) 回复 编辑
      • 楼主你好,请教一下:假如我访问www.awaimai.com 让其指定默认的控制器和操作为 site/index 就是www.awaimai.com/site/index 等于www.awaimai.com
        keone 3个月前 (04-10) 回复 编辑
  38. 楼主你好,请教一下:假如我访问www.awaimai.com 让其指定默认的控制器和操作为 site/index 就是www.awaimai.com/site/index 等于www.awaimai.com
    keone 3个月前 (04-10) 回复 编辑
    • 办法是,修改Core.php文件,将route()方法中的$controllerName = 'Index';$action = 'index';的值改为需要的内容。
      歪麦 3个月前 (04-10) 回复 编辑
      • 我的意思是能不能不加/site/index 这种,然后直接访问网址www.awaimai.com就能访问到www.awaimai.com/site/index, 我现在如果不加控制器名和方法名就会报错
        keone 3个月前 (04-10) 回复 编辑
      • 懂了!谢谢
        keone 3个月前 (04-10) 回复 编辑
  39. 兄弟 请问你接不接私活
    JUNLIANG 3个月前 (04-11) 回复 编辑
    • 这个嘛,私聊啦 🙂
      歪麦 3个月前 (04-11) 回复 编辑
  40. 楼主请问一下,,我想做前后台,该怎么实现,目前我只能做一个前台,要怎样分出后台应用
    dengyun 3个月前 (04-13) 回复 编辑
    • 暂时没做分模块呢,如果要做前后台,加上模块支持就可以啦
      歪麦 3个月前 (04-13) 回复 编辑
  41. 这是我见过的最好的PHP MVC入门教程了,感谢博主 😀 已小额赞助,多写些经典的 ❗ ❗
    往上 3个月前 (04-13) 回复 编辑
  42. 也是Fatal error: Class 'IndexController' not found in D:\phpStudy\WWW\demo\todo\fastphp\Core.php on line 44 这个错 最后发现是路径少了个杠:D:\phpStudy\WWW\demo\todo/application/controllersIndexController.class.php 😈
    mrsli 3个月前 (04-19) 回复 编辑
    • 你如何解决的呢?
      歪麦 3个月前 (04-19) 回复 编辑
      • 在Core.php的loadClass方法中: $controllers = APP_PATH.'application/controllers' . $class . '.class.php'; 这句controllers后面少了个斜杠: 就是这样:$controllers = APP_PATH.'application/controllers/' . $class . '.class.php';
        mrsli 3个月前 (04-19) 回复 编辑
        • 很细节的地方 🙄
          歪麦 3个月前 (04-19) 回复 编辑
  43. Fatal error: Uncaught Error: Class '/ItemController' not found in D:\projects\aureview\frame\Core.php on line 45 ( ! ) Error: Class '/ItemController' not found in D:\projects\aureview\frame\Core.php on line 45
    jcplus 2个月前 (05-01) 回复 编辑
    • 有没有额外说明?
      歪麦 2个月前 (05-01) 回复 编辑
      • 目录结构都和教程的一样。 fastphp - - Controller.class.php - Core.php - fastphp.php - Model.class.php - Sql.class.php - View.class.php ItemController.php在application > controller目录下
        jcplus 2个月前 (05-01) 回复 编辑
        • 直接git clone代码是否有同样问题呢?
          歪麦 2个月前 (05-01) 回复 编辑
          • 我是顺着教程走下来的,和你的github的项目比较了一下发现你的教程里说的不一样,比如教程里没说views目录下还有一个layout.php。教程里说的ItemController.php其实不对,你的项目里的是ItemController.class.php。另外教程里也没提到还有一个文件叫做IndexController.class.php,我补充上文件并且改名之后就没问题了。
            jcplus 2个月前 (05-02) 编辑
          • 好的,问题已修复并优化了框架。
            歪麦 2个月前 (05-04) 编辑
          • 网址上输入localhost/fastphp 之后,,,提示Controller控制器不存在,,这是什么原因呢?
            followyounger 2个月前 (05-15) 编辑
          • 把localhost的站点目录设置为project目录,然后直接访问localhost呢?
            歪麦 2个月前 (05-15) 编辑
  44. 我如果想在数据库塞一些分类,比如按地域分,比如beijing。然后点击domain/beijing,正常会出现错误 Fatal error: BeijingController not found。 这个分类肯定不能是由一个地区就写一个controller的吧,那还不累死,而且内容都相同,肯定是调阅比如数据库跟这个地区挂钩的比如食物数据,人员数据等等。这样的话应该大概怎么写,能不能给点思路,谢谢。
    jcplus 2个月前 (05-15) 回复 编辑
    • 我在php7.1.2下调试提示有几处语法错误,可能是php7.1.2语法要求更规范的原因。例如在类属性成员定义出现语法错误:protected $_config = [];应修改为protected $_config = array();还有:(new Fastphp($config))->run();修改为:$runFrame = new Fastphp($config);$runFrame->run(); 现在的问题是:语法修正后调试出现"Controller控制器不存在",麻烦帮忙解决下。
      Romins 2个月前 (05-16) 回复 编辑
      • 我试了PHP7.1.4,没有出现这样的提示呢 PHP7中也是可以用[]代表数组的,提示控制器不存在可能是代码有遗漏。 请从github上克隆一份再试试。
        歪麦 2个月前 (05-16) 回复 编辑
        • 谢谢热心指导,我刚下载xampp7.1.4默认设置安装和从githib上重新克隆,在未编辑代码情况下,程序可以运行,但仍然把报“Contrpller控制器不存在”的提示,请问是不是我的php服务器设置不对?叧外关于语法错误的问题,我用的是dreamweaver cs6。早上提的语法错误还是有,只是不影响程序运行。打开文件有:此页可能具有仅可由服务器搜索到的动态相关文件,点击“搜索”就提示:语法错误
          Romins 2个月前 (05-16) 回复 编辑
          • 那是可以运行呢,还是报错呢?我在apache和nginx服务器下都试过呢,似乎都没有出现类似的问题 最好查一下apache的log日志,查找一下具体原因
            歪麦 2个月前 (05-17) 编辑
    • 一般来说,这种直接通过表单提交的,用一个控制器就可以了。 比如创建一个area的控制器、一个area的model。 控制器负责接受处理表单数据,area负责读写数据库。 假设要插入beijing这个分类,就可以在表单里面用一个input/select等HTML标签定义,提交后发给控制器。 控制器再传给model写入数据库,这样就可以了。
      歪麦 2个月前 (05-16) 回复 编辑
      • 关于表单那个,网上有现成的例子吗,或者说我要想搜索例子的话用什么关键词比较准确?
        jcplus 2个月前 (05-16) 回复 编辑
        • 可以看看这个是否符合:http://www.runoob.com/php/php-forms.html
          歪麦 2个月前 (05-17) 回复 编辑
  45. 还是跟着我之前询问的地域那个问题,我自己创建了一个region的controller和index的view,但是现在遇到了一个思路上的问题。假设路径会是region/beijing或者region/shanghai,这样的话我是不是要为每个地点都建立一个class,但是它们其实内容都差不多。有没有办法只创建一个class,然后用户访问region/beijing的时候,去数据库的region表找有没有beijing,如果有就显示beijing的内容,没有就显示没有该地名
    jcplus 2个月前 (05-23) 回复 编辑
    • 也不一定都创建控制器呀,像这种:
      region/index?name=beijing
      region/index?name=shanghai
      ...
      
      这样不是也可以吗?
      歪麦 1个月前 (05-24) 回复 编辑
      • 理解了,但是用这样的方式可以写成region/Beijing吗?
        jcplus 1个月前 (05-24) 回复 编辑
        • region是控制器,beijing是操作名,在控制器里面增加一个操作就可以了 参数也可以做成这样:region/view/beijing,只要路由里面规定好就行
          歪麦 1个月前 (05-24) 回复 编辑
  46. 歪麦,我是刚学php的新手,我有个疑问,每个控制器都要继承Controller基类,但这个Controller基类是什么时候引入进去的?
    阿辉 1个月前 (05-23) 回复 编辑
    • Fastphp.php里面的run()方法注册了自动类加载spl_autoload_register(array($this, 'loadClass')); 因为子类继承了父类,所以PHP会去根据loadClass()方法去寻找该父类文件,并include进来。 可以研究下PHP的类自动加载。
      歪麦 1个月前 (05-24) 回复 编辑
  47. 我发现model里面没有任何例子,能增加一个简单的model的例子吗
    jcplus 1个月前 (05-24) 回复 编辑
    • 感谢建议,已经加上了
      歪麦 1个月前 (05-26) 回复 编辑
  48. Not Found The requested URL /item/add was not found on this server. 报了这个错,是我有哪儿没有配置吗? 🙄
    ethan 1个月前 (05-25) 回复 编辑
    • 应该是.htaccess文件没配置好,或者nginx的跳转未配置。
      歪麦 1个月前 (05-25) 回复 编辑
  49. 作者能简单的解释一下 spl_autoload_register( array( $this, 'loadClass' ) ); $this->setReporting(); $this->removeMagicQuotes(); $this->unregisterGlobals(); $this->route();
    jcplus 1个月前 (05-29) 回复 编辑
    • 调用本类中的方法,每个方法都有独自的注释说明的,请往下看。
      歪麦 1个月前 (05-30) 回复 编辑
  50. "如果文件或者目录真实存在,则直接访问存在的文件/目录。比如,静态文件static/css/main.css真实存在,就可以直接访问它。" 问题:project/application/下的MVC以及config等也是真实存在的文件和目录,也是可以直接访问的吗?如果使用rewrite规则将请求全部重定向到index.php,根据楼主Apache(Nginx)的配置,并未对静态文件和php脚本区分开来,只是用存在与否进行区分,可是如果直接访问php脚本呢
    taylor 1个月前 (06-05) 回复 编辑
    • 如果直接访问,也可以,但是因为没有echo等输出语句,所以看到的是空白的。 如果访问的是控制器、或者model、或者其他核心类,因为是类,没有指明方法名也是没有输出的。 如果要安全一点,那就在每个头加上这样一句:
      if (!defined('APP_PATH')) {
      	exit('Access Denied!');
      }
      
      没有从index.php走的访问一律提示无权限。
      歪麦 1个月前 (06-05) 回复 编辑
      • 赞同,因为框架MVC或config一般不会直接echo输出,所有直接访问是空白。在每个头上加上这句,也是保证安全,同时需要新增一个index.html(Access Denied)文件放在每层目录中,防止文件和目录被攻击者一览无余~类似于CI。还有一种比较好的方法就是在Nginx或Apache中配置location:涉及静态文件(.css/.js/.jpg等)可直接访问,涉及到php脚本全部重定向到index.php入口文件
        taylor 1个月前 (06-06) 回复 编辑
  51. LzController鎺у埗鍣ㄤ笉瀛樺湪,楼主,这是地址错误?
    ss 4周前 (06-11) 回复 编辑
    • 乱码呢?
      歪麦 4周前 (06-12) 回复 编辑
      • 一直说控制器不存在是什么情况
        ss 3周前 (06-13) 回复 编辑
        • 是我访问http://localhost/lz/indexphp错了,才会一直说控制器不存在。 Not Found The requested URL /lz/Item/index was not found on this server. 又出现新问题了
          ss 3周前 (06-13) 回复 编辑
          • 为啥中间多了个lz?
            歪麦 2周前 (06-22) 编辑
  52. 一直报控制器不存在怎么办
    zz 3周前 (06-16) 回复 编辑
    • 那就是确实没有这个控制器,或者nginx配置:
              location / {
                  try_files $uri $uri/ /index.php$args;
              }
      
      歪麦 2周前 (06-22) 回复 编辑
  53. 有个地方要更正一下,要把 application/views/ 下的 item 改成 Item(大写),否则报错:Warning: include(/home/*/*/project/application/views/Item/index.php): failed to open stream: No such file or directory in /home/*/*/project/fastphp/View.php on line 41 因为,你在用程序 将 item 的首字母大写了,如果不改 那就找到不文件夹喽! 调试了半天,才发现~ 还有这个程序的效果是什么?只有 全部条目,管理条目?但是 添加了 ,也没见到添加到哪里了?
    请叫我雷锋 3周前 (06-17) 回复 编辑
    • 嗯,如果系统是Linux,因为大小写敏感,确实会存在这个问题 。 已经修改了,views下面的目录和文件全部用小写。 另外,添加条目了之后,在“全部条目”下是可以看到新增的记录的。
      歪麦 2周前 (06-22) 回复 编辑
      • 这个真心没有,全部条目 -》 新建 -》 管理条目 -》点击添加以后 -》成功添加0条记录 返回 -》 跳转到 全部条目 -》然而没看任何记录
        请叫我雷锋 2周前 (06-26) 回复 编辑
        • 说明数据库没写成功
          歪麦 1周前 (06-28) 回复 编辑
  54. 我在View.class.php里面修改了这行 public function render( $codec = 'html' ) 然后在我自己的MyController 里面的index()调用的时候用了$this->render( 'json' );就报错说我那个render() 有missing 1 argument
    jcplus 3周前 (06-18) 回复 编辑
    • Controller.php里面还有用了View对象的方法,
          // 渲染视图
          public function render()
          {
              $this->_view->render();
          }
      
      一般像你这个情况,建议重新加一个方法,请参看面向对象设计原则的开闭原则
      歪麦 2周前 (06-22) 回复 编辑
  55. ProjectController.php不存在
    同舟共济 1周前 (06-27) 回复 编辑
    • 确实没有这个控制器的,要自己创建,默认有`ItemController`
      歪麦 1周前 (06-28) 回复 编辑
  56. 你这好多坑啊!
    11 1周前 (06-27) 回复 编辑
    • 比如哪里?
      歪麦 1周前 (06-28) 回复 编辑
      • 解决啦,你网上的代码,和github上的有区别,问题解决!
        11 1周前 (06-28) 回复 编辑
        • OK,可能更新的时候有遗漏,再同步下。
          歪麦 1周前 (06-28) 回复 编辑
  57. 不明白为什么model类为啥要继承SQL,为什么不通过一个SQL实例来操作数据库。
    小可爱 29分钟前 回复 编辑