配置文件

Viswoole 的应用配置集中存放在项目根目录的 config/ 目录下,由 Viswoole\Core\Config 统一加载与解析。本篇是配置文件格式、读取 API 与懒加载机制的完整参考。

目录结构

text
config/
├── app.php                 # 应用配置:调试、时区、服务提供者、命令
├── server.php              # Swoole 服务定义
├── router.php              # 路由全局配置(含路由缓存、API 文档)
├── database.php            # 数据库通道配置
├── cache.php               # 缓存存储配置
├── log.php                 # 日志通道配置
├── task.php                # 异步任务配置
├── listens.php             # 事件监听注册入口
├── lazy/                   # 懒加载配置目录(AppInitialized 后加载)
│   └── middleware.php      #   全局中间件注册
└── route/
    └── route.php           # 编程式路由定义(非配置,由路由器加载)

只加载项目 config 目录

框架仅从项目根目录config/ 加载配置。依赖包内提供的默认配置需通过 php viswoole vendor:publish 发布到项目后修改,直接修改依赖包内的配置文件会在更新时丢失。

支持的文件格式

config/ 下的所有文件按扩展名分发到对应解析器,文件名(不含扩展名)作为该文件配置的一级键:

扩展名解析方式说明
phpinclude执行并取返回值推荐,支持表达式与条件逻辑
yml / yamlyaml_parse_file()需要安装 yaml 扩展;未安装时该文件被静默跳过(解析为空)
iniparse_ini_file()(typed 扫描器)true/false/数字 自动转对应类型
jsonjson_decode()解析失败会抛出 RuntimeException,错误信息含文件路径
其他扩展名忽略不解析

PHP 格式(推荐)

php
<?php
declare(strict_types=1);

return [
    // 支持表达式与条件逻辑
    'debug' => env('app_debug', true),
    'services' => env('APP_ENV') === 'local'
        ? [\App\Provider\DevProvider::class]
        : [],
];

JSON 格式

json
{
  "menu": {
    "home": "/",
    "about": "/about"
  }
}

YAML 格式

yaml
database:
  host: localhost
  port: 3306

INI 格式

ini
; 支持分节,节名成为一级数组键
[features]
registration = true
rate_limiting = false

读取配置

config() 助手函数

php
// 文件名即一级键
$debug = config('app.debug');                            // 对应 config/app.php

// 点号(.)分隔的多级访问
$port = config('server.servers.http.construct.port');    // 9501

// 带默认值:键不存在(或值为 null)时返回默认值
$timeout = config('database.channels.default.options.timeout', 5);

// 只传文件名返回整个文件的配置数组
$appConfig = config('app');

// 不传参数返回全部配置
$all = config();

config() 只读

config() 是纯读取助手,没有写入能力;运行期写入请使用 Config 门面的 set() 方法。

Config 门面

php
use Viswoole\Core\Facade\Config;

// 读取(等价 config())
Config::get('app.debug');
Config::get('app.not_exists', 'default_value');

// 检测存在性(值为 null 视为不存在)
Config::has('app.debug');      // true
Config::has('app.not_exists'); // false

// 写入:单条
Config::set('app.debug', false);

// 写入:批量(键名支持点号多级)
Config::set([
    'app.debug' => false,
    'app.default_timezone' => 'UTC',
]);

关于 set() 的进程内语义

Config::set() 只修改当前进程内存中的配置池,不写入任何文件:

  • 进程重启后恢复为文件中的值;
  • 写入时自动创建缺失的中间层级(点号路径上的键不存在时创建为空数组再深入);
  • 配置键区分大小写(框架以大小写敏感模式加载),写入与读取的键名大小写必须一致。

Swoole 多进程环境

配置在 Master 进程启动时加载,各 Worker 进程继承的是启动那一刻的快照。Config::set() 只影响执行它的当前进程,不会同步到其他 Worker——运行期动态调整全局配置需借助 AppInitialized 事件或 Swoole 事件在启动阶段完成,而非请求期随意修改。

同名文件合并

同一目录下允许同名但不同扩展名的配置文件(如 app.phpapp.json),框架按文件名顺序逐个解析后数组合并,后解析者覆盖先解析者的同名键:

php
// config/app.php
return ['name' => 'App', 'debug' => true];

// config/app.json
{"name": "Override", "version": "1.0"}

合并结果:['name' => 'App', 'debug' => true, 'version' => '1.0']app.json 先于 app.php 解析)。

建议避免同名多格式

合并顺序依赖文件名排序,行为较为隐式。除刻意分层覆盖外,建议一个配置文件只用一种格式。

核心配置文件速览

各配置文件的完整键位说明见对应功能章节,此处仅作索引:

文件一级键关键配置详见
app.phpappdebugdefault_timezoneservices[]commands[]项目结构
server.phpserverdefault_start_serverservers.*、全局 options/events生产环境配置
router.phproutercase_sensitiveroute_config_files[]cacheapi_doc路由配置
database.phpdatabasedefaultdebugchannels.*数据库配置
cache.phpcachedefaultstores.*缓存
log.phplogdefaulttype_channelchannels.*日志配置
task.phptaskstoreexpiretopics异步任务
listens.php直接调用 Event::on() 注册监听事件系统

懒加载机制

工作原理

config/lazy/ 子目录中的配置不会在进程启动时立即加载。Config 在构造时加载主目录后,会监听 AppInitialized 事件,待应用初始化完成后再加载 lazy/ 目录:

text
进程启动
  ├─ 加载 config/*.php                 ← 立即加载
  ├─ 注册服务提供者、绑定核心组件
  ├─ 触发 AppInitialized 事件
  │    └─ Config 加载 config/lazy/*.php ← 此刻才加载
  └─ 服务就绪,开始处理请求

这样做的收益:启动阶段跳过非关键配置的解析与执行,减少启动时间与内存占用。

内置的懒加载文件

框架默认在 config/lazy/middleware.php 中注册全局中间件:

php
<?php
declare(strict_types=1);

use Viswoole\Core\Facade\Middleware;
use Viswoole\Core\Middlewares\AllowCrossDomain;

// 该中间件用于解决跨域请求问题
Middleware::register(AllowCrossDomain::class);

它不是"返回数组"的配置

lazy/middleware.php 是一段被执行的注册代码而非返回数组的配置文件——由于加载发生在 AppInitialized 之后,此时中间件门面已可用,可以安全注册。因此它无法通过 config('middleware.xxx') 访问。

自定义懒加载配置

普通的懒加载配置文件返回数组,访问方式与主目录配置完全一致:

php
<?php
// config/lazy/permissions.php —— 权限矩阵数据量大,延迟加载
declare(strict_types=1);

return [
    'permissions' => [
        'user.create' => '创建用户',
        'user.read'   => '查看用户',
    ],
    'roles' => [
        'admin' => ['*'],
        'viewer' => ['user.read'],
    ],
];
php
// 请求处理阶段访问,安全
$permissions = config('permissions.permissions');

适合与不适合放入 lazy/

适合懒加载不适合懒加载
路由解析后才用到的配置(如中间件)启动必需的核心配置(appservercachelogdatabase 等)
数据量大的业务配置(权限矩阵、菜单树)启动阶段(服务提供者 register())就要读取的配置
特定功能才用到的第三方 SDK 配置被立即加载配置引用的配置

时序红线

AppInitialized 之前访问懒加载配置会得到 null

php
use Viswoole\Core\Service\Provider;

// ❌ 错误:Provider 的 register() 在 AppInitialized 之前执行
//    此时 config/lazy/permissions.php 尚未加载
class AppProvider extends Provider
{
    public function register(): void
    {
        config('permissions.permissions');   // null!
    }
}

// ✅ 正确:请求处理阶段访问,此时懒加载已完成
class PermissionService
{
    public function can(string $permission): bool
    {
        return in_array($permission, config('permissions.permissions', []), true);
    }
}

同理,主目录配置文件中也不要引用懒加载配置——依赖链应保持在同一加载批次(要么都立即加载,要么都懒加载)。

下一步