PHP 写个简单的框架

wen PHP项目 3

本文目录导读:

PHP 写个简单的框架

  1. 目录导读
  2. 常见问题问答(FAQ)
  3. 总结与扩展建议

从零手写一个PHP简易框架:核心架构与实战指南**


目录导读

  1. 为什么你需要“造轮子”?——理解框架的本质
  2. 环境准备与目录结构设计
  3. 核心组件一:前端控制器(入口文件)与路由分发
  4. 核心组件二:请求与响应对象封装
  5. 核心组件三:简单的数据库连接与查询构造器
  6. 核心组件四:模板引擎(原生PHP视图渲染)
  7. 错误处理与调试机制
  8. 常见问题问答(FAQ)
  9. 总结与扩展建议

为什么你需要“造轮子”?

虽然Laravel、ThinkPHP功能强大,但直接阅读源码往往令人望而生畏,手动编写一个微型框架,能让你彻底理解MVC(模型-视图-控制器)的运行机制、HTTP请求的生命周期,以及“约定优于配置”的设计思想,这不仅是面试加分项,更能提升你排查复杂Bug的能力,我们的目标极简:路由 → 控制器 → 模型 → 视图,代码量控制在500行以内。

环境准备与目录结构设计

建议使用PHP 7.4+版本,开启ini_set('display_errors', 1),生成如下结构:

myframework/
├── app/
│   ├── controllers/   # 控制器
│   ├── models/        # 模型
│   └── views/         # 视图模板
├── core/              # 核心类
│   ├── Router.php
│   ├── Request.php
│   ├── Response.php
│   └── Database.php
└── public/            # Web根目录
    └── index.php      # 唯一入口

关键点:将public设为Apache/Nginx的站点根目录,防止直接访问源码文件。

前端控制器与路由分发

所有请求都定向到index.php,实现统一入口,编写Router.php

class Router {
    private $routes = [];
    public function add($uri, $handler) {
        $this->routes[$uri] = $handler;
    }
    public function dispatch(Request $request) {
        $uri = $request->getPath();
        if (isset($this->routes[$uri])) {
            [$controller, $action] = explode('@', $this->routes[$uri]);
            $obj = new $controller();
            return $obj->$action($request);
        }
        throw new Exception('404 Not Found');
    }
}

在入口文件中注册路由:

$router->add('/', 'HomeController@index');
$router->add('/user', 'UserController@show');

请求与响应对象

封装$_SERVER$_POST数据:

class Request {
    public function getPath() {
        $path = $_SERVER['REQUEST_URI'] ?? '/';
        $position = strpos($path, '?');
        return $position === false ? $path : substr($path, 0, $position);
    }
    public function getMethod() { return $_SERVER['REQUEST_METHOD']; }
    public function input($key) { return $_POST[$key] ?? $_GET[$key] ?? null; }
}
class Response {
    public function json($data) {
        header('Content-Type: application/json');
        echo json_encode($data);
    }
}

优势:控制器代码不再直接操作超全局变量,便于单元测试。

数据库连接与查询构造器

使用PDO预处理防注入,实现一个极简链式调用:

class Database {
    private $pdo;
    public function __construct($config) {
        $this->pdo = new PDO($config['dsn'], $config['user'], $config['pass']);
    }
    public function table($table) {
        $this->table = $table;
        return $this; // 链式
    }
    public function where($column, $value) {
        $this->wheres[] = "$column = ?";
        $this->bindings[] = $value;
        return $this;
    }
    public function get() {
        $sql = "SELECT * FROM {$this->table}";
        if ($this->wheres) {
            $sql .= " WHERE " . implode(' AND ', $this->wheres);
        }
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($this->bindings);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

用法:$db->table('users')->where('id', 1)->get();

原生视图渲染

为避免引入复杂模板语法,直接使用PHP作为模板引擎,封装View类:

class View {
    public static function render($template, $data = []) {
        extract($data); // 将关联数组转为变量
        include __DIR__ . "/../app/views/{$template}.php";
    }
}

在视图中直接写<h1><?= $title ?></h1>即可,保持简单高效。

错误处理与调试

注册两个全局回调:

set_error_handler(function($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});
set_exception_handler(function($e) {
    http_response_code(500);
    echo "<pre>异常: " . $e->getMessage() . "\n文件: " . $e->getFile() . ":" . $e->getLine() . "</pre>";
});

开发环境可输出详细堆栈,生产环境则记录日志并显示友好页面。


常见问题问答(FAQ)

Q1:这个框架能用于生产环境吗? 不能,它缺少中间件、依赖注入、事件系统、缓存机制等高级特性,仅适用于学习或极简API原型开发。

Q2:如何支持RESTful风格的URL? 可以修改Router::dispatch(),用正则匹配/user/(\d+),提取参数传入控制器方法。

Q3:为什么不用Composer的第三方包? 本框架核心目的就是展示“零依赖”精神,帮助你理解底层逻辑,实际项目中,建议通过Composer引入filp/whoops作为错误处理,symfony/http-foundation替代自定义Request。

Q4:如何扩展自己的助手函数? 在入口文件index.php中定义全局函数,或创建core/helpers.php并用require_once引入。

Q5:性能如何优化? 可用OPcache开启字节码缓存;路由映射改为静态数组;数据库连接改为单例模式。


总结与扩展建议

本文实现的极简框架核心思想是单一入口 + 路由映射 + MVC分离,扩展方向建议:

  • 增加路由参数(如{id})匹配规则
  • 引入命名空间与PSR-4自动加载
  • 实现Container容器解耦类依赖
  • 添加基于中间件的权限验证

只有亲手“造过轮子”,你在使用工业级框架时才能知其然更知其所以然,下次遇到“该用哪个框架”的争论时,你可以自信地说:“我不需要框架,因为我就是框架的缔造者。” 但请记住,真正的专业是知道何时造轮子,何时买轮子——学习时大胆造,工作中谨慎选。

抱歉,评论功能暂时关闭!