StartMVC开发手册

可以快速上手的开发文档

手册目录

配置文件

配置文件

配置文件位于项目根目录的 config 目录下。框架自带的文件有:

  • common.php —— 系统基础配置(调试、时区、默认模块、URL 规则、Session / Cookie 前缀、可信代理等)
  • session.php —— Session 安全配置(HttpOnly、Secure、SameSite、生命周期)
  • cookie.php —— Cookie 默认安全策略
  • csrf.php —— CSRF 防护配置(有效期、字段名、免校验路径)
  • database.php —— 数据库连接配置
  • cache.php —— 缓存驱动配置
  • log.php —— 日志配置
  • route.php —— 路由定义
  • middleware.php —— 中间件别名与全局中间件配置
  • pagination.php —— 分页配置
  • view.php —— 视图 / 模板配置

除自带文件外,还可以在 config 目录下新增任意配置文件,用 config('文件名.键名') 访问,首次访问时自动按需加载。

配置只有一个来源:config/ 就是你的配置目录,框架本体不带默认配置文件。升级时只需替换 startmvc/ 目录,config/ 不会被覆盖,改过的值不会丢。

配置加载机制

配置系统采用自动按需加载:

  • common.php 在首次使用配置系统时自动加载
  • 其他分组在首次被访问时自动加载(无需手动预加载)
  • 加载过的分组会被缓存,不会重复读文件

覆盖规则

每个分组在加载时按顺序合并三处,后者覆盖前者:

  1. config/{分组}.php —— 你直接修改的文件
  2. config/{ENV}.php 里的同名分组键(ENV 取值见 boot.php,如 development / production)
  3. config/local.php 里的同名分组键 —— 开发者个人配置,通常不纳入版本控制

优先级:local.php > {ENV}.php > {分组}.php。合并是递归的:关联数组逐键合并,只覆盖你写到的键;列表(连续数字下标的数组,例如 csrf.exclude)整体替换。

环境覆盖怎么写

顶层键就是分组名,即 config 下的文件名(不含 .php):

// config/local.php
return [
 'common' => ['debug' => false],
 'database' => ['connections' => ['mysql' => ['password' => '123456']]],
];

上面只改了两处:common.debug 和 mysql 的密码。数据库的 host、端口、前缀、字符集等其余键原样保留——不需要把整份 database.php 复制过来。

注意:顶层键必须是分组名。直接写 ['debug' => false] 这种扁平写法不会生效,也不会报错——配置系统只会去找名为 debug 的分组,而它不存在。想改 common 的键,请写成 ['common' => ['debug' => false]]。

使用方法

助手函数 config()

框架提供了 config() 助手函数,是访问配置的最简单方式:

// 获取所有配置
$allConfig = config();

// 获取特定配置项(自动加载对应配置文件)
$debug = config('debug');
$dbHost = config('database.connections.mysql.host');
$secure = config('session.cookie_secure');

// 读取配置项,并在不存在时给出默认值(第二个参数是默认值,不是"设置")
$host = config('database.connections.mysql.host', 'localhost');

// 批量设置配置(传数组)
config([
 'site.title' => '我的网站',
 'site.description' => '网站描述'
]);

// 显式加载某个配置文件(可选,向后兼容)
$dbConfig = config('@database');

config() 函数的实现具有以下特点:

  1. 当不带参数调用时,返回所有已加载的配置(Config::get())
  2. 当参数以 @ 开头时,会调用 Config::load() 按需加载指定的配置文件
  3. 当参数是数组时,会循环设置多个配置项(Config::set())
  4. 当有两个参数时,第二个参数是默认值,即读取配置项、不存在时返回该默认值
  5. 其他情况下,获取指定的配置项

直接使用 Config 类

也可以直接使用 Config 类:

use startmvc\core\Config;

// 获取配置
$host = Config::get('database.connections.mysql.host');

// 提供默认值的用法 - 当配置项不存在时返回默认值
$host = Config::get('database.connections.mysql.host', 'localhost');

// 设置配置
Config::set('debug', false);

// 检查配置是否存在
if (Config::has('cache.redis.port')) {
 // 使用配置
}

// 加载特定配置文件(返回整个分组数组,文件不存在时返回 null)
$redisConfig = Config::load('cache');

// 获取配置分组
$cacheSettings = Config::group('cache');

点语法

第一段是分组名(配置文件名),之后逐级对应数组的键:

$driver = config('database.driver'); // 'mysql'
$mysqlHost = config('database.connections.mysql.host'); // 'localhost'
$secure = config('session.cookie_secure'); // 'auto'
$tokenName = config('csrf.token_name'); // 'csrf_token'

common.php 里的扁平键可以省掉前缀,直接读短键:

config('debug'); // 等价于 config('common.debug')
config('url_suffix'); // '.html'

分组名和 common 的键重名时,分组优先。例如存在 config/session.php 时,config('session.cookie_secure') 读的是那个文件。

示例配置文件

// config/common.php
return [
 'debug' => true, // Debug模式,开发过程中开启,生产环境中请关闭
 'trace' => true, // 是否附加调试追踪面板(仅对 HTML 页面生效)
 'route_cache' => true, // 路由编译缓存,以 config/route.php 修改时间 + 框架版本号为失效键
 'timezone' => 'Asia/Shanghai', // 系统时区
 'url_suffix' => '.html', // URL后缀
 'default_module' => 'home', // 默认模块
 'default_controller' => 'Index', // 默认控制器
 'default_action' => 'index', // 默认方法
 'urlrewrite' => true, // 是否Url重写,隐藏index.php
 'session_prefix' => '', // Session前缀
 'cookie_prefix' => '', // Cookie前缀
 'locale' => 'zh_cn', // 指定默认语言,小写
 'db_auto_connect' => true, // 是否开启数据库自动连接
 'theme' => '', // 指定模板子目录,方便多风格使用
 'trusted_proxies' => [], // 可信代理IP:仅当 REMOTE_ADDR 命中时才信任 X-Forwarded-For
];

// config/session.php
return [
 'cookie_httponly' => true, // 防止 JavaScript 访问 Cookie
 'cookie_secure' => 'auto', // true 强制 HTTPS / false 关闭 / 'auto' 自动检测
 'cookie_samesite' => 'Lax', // Lax / Strict / None(None 必须配合 secure)
 'use_only_cookies' => true, // 只使用 Cookie 存储会话 ID
 'cookie_lifetime' => 7200, // 会话 Cookie 生存时间(秒)
 'gc_maxlifetime' => 7200, // 垃圾回收时间(秒)
];

// config/cookie.php
return [
 'cookie_secure' => 'auto', // Cookie::set / delete 的默认安全策略,可被调用参数覆盖
 'cookie_samesite' => 'Lax',
];

// config/csrf.php
return [
 'token_lifetime' => 3600, // Token 有效期(秒)
 'token_name' => 'csrf_token', // Token 字段名
 'auto_delete' => false, // 验证后是否自动删除(false=可重复使用)
 'exclude' => [ // 无需校验的路径,支持 * 通配符
 // 'api/webhook',
 // 'api/open/*',
 ],
];

// config/database.php(仅节选 mysql 连接)
return [
 'driver' => 'mysql',
 'connections' => [
 'mysql' => [
 'host' => 'localhost',
 'database' => 'startmvc',
 'username' => 'root',
 'password' => '',
 'charset' => 'utf8',
 'port' => 3306,
 'prefix' => 'sm_',
 'cachetime' => 3600,
 'debug' => false, // 报错时输出详细SQL,生产环境必须false
 'log_sql' => 2, // SQL日志:0关闭 1只记写操作 2全部记录(lastQuery与调试条用)
 'log_sql_max' => 1000, // 日志最多保留条数(0=不限),防止长跑脚本内存膨胀
 'options' => [], // 连接选项(如SSL证书等,可选)
 ],
 ],
];

// config/cache.php
return [
 'drive' => 'file', //默认驱动支持 file,redis,memcached 缓存
 'file' => [
 'cacheDir' => 'cache/',
 'cacheTime' => 3600
 ],
 'redis' => [
 'host' => '127.0.0.1',
 'port' => 6379,
 'password' => '',
 'database' => 0,
 'cacheTime' => 3600
 ],
 'memcached' => [
 'host' => '127.0.0.1',
 'port' => 11211,
 'cacheTime' => 3600
 ],
];

// config/log.php
return [
 'enabled' => true, // 日志总开关,false 时所有写入直接丢弃
 'path' => null, // 日志目录(绝对路径),留空则使用 runtime/logs
 'level' => 'debug', // 最低记录级别,低于该级别的日志被静默丢弃
 'split' => true, // 是否按级别分文件:true 得到 2026-09-12_error.log,false 得到 2026-09-12.log
];

日志配置

框架内所有日志(含 Exception 异常处理器的错误记录)都统一经由 startmvc\core\Logger 写入,不再各自拼路径、各写各的文件。日志相关的四项配置见上方 config/log.php。

常用写法:

use startmvc\core\Logger;

$logger = new Logger();
$logger->info('用户登录', ['id' => 42]); // [2026-09-12 21:30:00] INFO: 用户登录
$logger->warning('库存不足');
$logger->error('支付回调处理失败');

要点:

  • 日志级别按严重度递增为 debug < info < notice < warning < error < critical < alert < emergency,八个级别都有对应的快捷方法(debug() / info() / ... / emergency())。传入未定义的级别会抛出 InvalidArgumentException。
  • 写入采用追加方式并加锁,写入失败只返回 false、绝不抛异常,避免日志问题影响业务(尤其是异常处理器里的日志记录)。
  • 日志目录不可写时会自动退化到系统临时目录(sys_get_temp_dir()/startmvc-logs),仍不可用则静默丢弃。
  • 生产环境建议把 level 调为 warning,避免 debug 日志堆积。

使用示例

// 获取系统调试模式
$debug = config('debug');

// 获取数据库连接信息(自动加载 database.php)
$db = config('database');
$dbDriver = config('database.driver');
$dbHost = config('database.connections.mysql.host');
$dbName = config('database.connections.mysql.database');

// 批量修改配置
config([
 'debug' => false,
 'trace' => false,
]);

// 直接用 Config 类设置单个配置项
Config::set('debug', false);

// 检查配置是否存在
if (Config::has('database.connections.mysql.port')) {
 $port = config('database.connections.mysql.port');
} else {
 $port = 3306;
}

// 获取缓存配置(自动加载 cache.php)
$cacheDriver = config('cache.drive');
$redisHost = config('cache.redis.host');

本地覆盖示例

开发机和生产机的数据库密码不同,不需要改 config/database.php,只写一份 config/local.php(不提交到版本库):

// config/local.php
return [
 'common' => ['debug' => true],
 'database' => [
 'connections' => [
 'mysql' => ['password' => '123456'],
 ],
 ],
];

只想改一两个值、又不想引入 local.php 时,用 .env 更直接:config/database.php 里已经用 env('DB_PASSWORD') 读取,密码写在 .env 即可,配置文件本身可以进版本库。