PHPackages                             muzk6/jdi - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. muzk6/jdi

ActiveLibrary

muzk6/jdi
=========

PHP Framework

v1.7.0(1y ago)5117MITPHPPHP ^7.1

Since Oct 7Pushed 6mo ago2 watchersCompare

[ Source](https://github.com/muzk6/jdi)[ Packagist](https://packagist.org/packages/muzk6/jdi)[ RSS](/packages/muzk6-jdi/feed)WikiDiscussions master Synced 6d ago

READMEChangelog (10)DependenciesVersions (43)Used By (0)

[jdi](https://github.com/muzk6/jdi.git)
=======================================

[](#jdi)

> PHP 框架 —— Just Do It
> 相关项目：
> [jdi-ops: JDI 框架的 OPS 运维后台](https://github.com/muzk6/jdi-ops)

起步
--

[](#起步)

### 安装

[](#安装)

`composer require muzk6/jdi`

### 基本用例

[](#基本用例)

#### 框架用例

[](#框架用例)

作为框架使用

*index.php*

```
require __DIR__ . '/vendor/autoload.php';

// 框架初始化
\JDI\App::init();

// 注册路由
route_get('/', function () {
    return 'Just Do It!';
});

// 分发路由
route_dispatch();
```

开启服务：`php -S 0.0.0.0:8080`

#### 库用例

[](#库用例)

无需`\JDI\App::init()`，可以直接作为库嵌入到现有项目使用

### 参数配置

[](#参数配置)

自定义配置：`\JDI\App::init(['config.debug' => false]);`

其它配置项参考下表：

配置项默认值描述config.debugtrue调试开发模式，用于显示错误信息、关闭视图模板缓存、关闭 opcacheconfig.path\_data&lt;jdi 根目录&gt;/data数据目录，保证有写权限config.path\_view&lt;jdi 根目录&gt;/views视图模板目录config.path\_config\_first&lt;空&gt;第一优先级配置目录，找不到配置文件时，就在第二优先级配置目录里找，以此类推config.path\_config\_second&lt;空&gt;第二优先级配置目录config.path\_config\_third&lt;jdi 根目录&gt;/config第三优先级配置目录，一般默认即可，取框架的默认配置文件config.timezonePRC时区config.session\_starttrue开启 sessionconfig.init\_handlernull容器初始化回调，null 时默认调用 \\JDI\\App::initHandler### 更多例子请 `cd` 到目录 `tests/feature`

[](#更多例子请-cd-到目录-testsfeature)

- 简单路由 `php -S 0.0.0.0:8080 router_simple.php`
- 中间件与路由 `php -S 0.0.0.0:8080 router_advanced.php`
- 经典 MVC `php -S 0.0.0.0:8080 router_mvc.php`

命名规范(仅仅建议)
----------

[](#命名规范仅仅建议)

- 变量名下划线，与数据库字段、数组键、URL中的参数统一
- 方法名小驼峰，与面向对象统一
- 函数名下划线，与面向过程、内置函数统一

路由
--

[](#路由)

### 注册路由

[](#注册路由)

- `route_get()` 注册回调 GET 请求
- `route_post()` 注册回调 POST 请求
- `route_any()` 注册回调任何请求
- `route_middleware()` 注册路由中间件，顺序执行，组内优先
- `route_group()` 路由分组，隔离中间件

其中参数 url: `/demo` 全匹配；`#/demo#` 正则匹配(`#`开头自动切换为正则模式)；更多高级用法可使用 `\JDI\Services\Router::addRoute`

### 用例

[](#用例)

#### 中间件

[](#中间件)

```
route_middleware(function () {
    echo '中间件a1'; // 这里为了测试才用 echo，实际开发时只用于处理逻辑而不需要打印
});

route_middleware(function () {
    echo '中间件a2';
});

route_group(function () {
    route_middleware(function () {
        echo '中间件b1';
    });

    route_get('/mid', function () {
        return 'Just Do It!';
    });
});

route_middleware(function () {
    echo '中间件a3';
});
```

GET 请求 `/mid` 输出：

```
中间件b1
中间件a1
中间件a2
Just Do It!
中间件a3

```

#### 异常处理

[](#异常处理)

```
// 不指定参数三，用默认方式
route_post('/xhr', function () {
    panic();
});

// 指定参数三，自定义异常处理
route_post('/doc', function () {
    panic('doc error');
}, function (Exception $exception) {
    if ($exception instanceof AppException) {
        // 只提示业务异常
        alert($exception->getMessage());
    } else {
        // 非业务异常不提示
        back();
    }
});
```

POST 请求 `/xhr` 输出：`{ "state": false, "code": 0, "message": "", "data": {} }`

POST 请求 `/doc` 输出 `alert()` 弹层：`doc error`

#### 模拟请求本地路由

[](#模拟请求本地路由)

```
route_get('/idnex', function() {
    return [input('get.da:i'), svc_auth()->isLogin()];
});

route_simulate('/idnex', ['da' => 10], 1010); // 注意在这之前不能调用 route_dispatch()
```

#### 路由的其它方法

[](#路由的其它方法)

- `\JDI\Services\Router::setStatus404Handler` 设置响应 404 的回调函数
- `\JDI\Services\Router::fireStatus404` 触发 404 错误
- `\JDI\Services\Router::getMatchedRoute` 成功匹配的路由
- `\JDI\Services\Router::getREMatches` URL 正则捕获项
- `\JDI\Services\Router::getException` 异常，通常用于在后置中间件做处理
- `\JDI\Services\Router::setResponseContent` 设置响应内容，通常用于在后置中间件改写响应内容
- `\JDI\Services\Router::getResponseContent` 获取响应内容

请求参数
----

[](#请求参数)

> 获取、过滤、表单验证、类型强转 请求参数 `$_GET,$_POST` 支持 `payload`

- 以下的验证失败时会抛出异常 \\JDI\\Exceptions\\AppException

### 不验证，一个一个获取

[](#不验证一个一个获取)

```
$first_name = input('first_name');
$last_name = input('last_name');
var_dump($first_name, $last_name);
```

### 不验证，统一获取

[](#不验证统一获取)

```
$request = request();
var_dump($request);
```

### 部分验证，一个一个获取

[](#部分验证一个一个获取)

```
$first_name = input('first_name');
$last_name = validate('last_name')->required()->get('名字');
var_dump($first_name, $last_name);
```

### 部分验证，统一获取

[](#部分验证统一获取)

```
validate('last_name')->required()->setTitle('名字');
$request = request();
var_dump($request);
```

### 串联短路方式验证（默认）

[](#串联短路方式验证默认)

遇到验证不通过时，立即终止后面的验证

```
validate('first_name')->required();
validate('last_name')->required()->setTitle('名字');
$request = request(); // 以串联短路方式验证
var_dump($request);
```

*串联结果*

```
{
    "state": false,
    "code": 10001000,
    "message": "参数错误",
    "data": {
        "first_name": "不能为空"
    }
}
```

### 并联验证

[](#并联验证)

即使前面的验证不通过，也会继续验证后面的字段

```
validate('first_name')->required();
validate('last_name')->required()->setTitle('名字');
$request = request(true); // 以并联方式验证
```

*并联结果*

```
{
    "state": false,
    "code": 10001000,
    "message": "参数错误",
    "data": {
        "first_name": "不能为空",
        "last_name": "名字不能为空"
    }
}
```

### `input()` 参数说明

[](#input-参数说明)

`'get.foo:i'` 中的类型转换`i`为整型，其它类型为：

NameTypeiintsstringbboolaarrayffloatddouble响应内容
----

[](#响应内容)

在路由回调里使用

- `return 'Just Do It!';` Just Do It!
- `return [];` { "state": true, "code": 0, "message": "", "data": {} }
- `return ['foo' => 1];` { "state": true, "code": 0, "message": "", "data": { "foo": 1 } }
- `return api_msg('保存成功');` { "state": true, "code": 0, "message": "保存成功", "data": {} }
- `panic();` { "state": false, "code": 0, "message": "", "data": {} }
- `panic('保存失败');` { "state": false, "code": 0, "message": "保存失败", "data": {} }
- `panic('保存失败', ['foo' => 1]);` { "state": false, "code": 0, "message": "保存失败", "data": { "foo": 1 } }
- `panic(10001000);` { "state": false, "code": 10001000, "message": "参数错误", "data": {} }; 参考翻译文件 lang\_zh\_CN.php
- `panic([10002001, 'name' => 'tom']);` { "state": false, "code": 10002001, "message": "欢迎 tom", "data": {} }

以上方式都是 `return api_json()` 的衍生，更多需求可直接调用 `api_json()`

其中与 `api_format()` 的关系是：`api_json()` 即 `json_encode(api_format())`

容器服务
----

[](#容器服务)

### 定义单例服务

[](#定义单例服务)

```
function svc_foo()
{
    return \JDI\App::singleton(__FUNCTION__, function () {
        return new Foo();
    });
}
```

### 覆盖

[](#覆盖)

如果上面的 `svc_foo()` 还未调用过，可以覆盖：

```
\JDI\App::set('svc_foo', function () {
    return new Bar();
});
```

如果要强制修改，可以先删除：

```
\JDI\App::unset('svc_foo');
```

PDO 数据库
-------

[](#pdo-数据库)

可以配置 MySQL, SQLite 等 PDO 支持的数据库

- 配置文件 `config/mysql.php`
- 用例参考 `tests/phpunit/Services/DBTest.php`

如果想同时使用 SQLite 等数据库, 复制 `mysql.php` 为新的数据库配置文件，按需配置 dsn，再注册容器即可(参考 `services.php` `svc_mysql()`)

`helpers` 其它辅助函数用例
------------------

[](#helpers-其它辅助函数用例)

#### `config()` 配置文件

[](#config-配置文件)

- `config('app.lang')`
- 例如第一、二优先级目录分别是 `config/dev/`, `config/common/`
- 依次搜索下面文件，存在时返回第一个结果的文件内容：
    - `config/dev/app.php`
    - `config/common/app.php`
    - `vendor/muzk6/jdi/config/app.php`
- `config(['app.lang' => 'en'])`设置 run-time 的配置

#### `trans()` 多语言文本

[](#trans-多语言文本)

- `trans(10001000)`
- 假设当前语言是`zh_CN`, 默认语言是`en`
- 依次搜索`lang_zh_CN.php, lang_en.php`, 存在`10001000`这个`key`时返回第一个结果内容，都不存在时返回`''`

#### `log_push()` 日志推入待刷写集合

[](#log_push-日志推入待刷写集合)

`log_push('test', ['foo', 'bar'], 'login')` 把内容写到`data/log/login_20190328.log`

各日志文件说明：

- `standard_xxx.log` PHP 标准错误处理程序写的日志，比较精简，但能记录 Fatal Error, Parse Error
- `error_xxx.log` 框架写的错误日志，比较详细
- `app_xxx.log` 用户写的默认日志，文件名可以修改，由 `log_push()` 参数3控制

通用日志字段场景：

```
log_push('test', ['user_id' => 123, '这里写日志']);
log_push('test', ['user_id' => 123, '另一处又写日志']);
```

如果像以上例子都要记录 `user_id`, 可以使用 `\JDI\Services\Log::setExtraData` 单独把 `user_id` 设置起来，后面调用 `log_push()` 时不需要再记录 `user_id`：

```
svc_log()->setExtraData('user_id', 123);

log_push('test', ['这里写日志']);
log_push('test', ['另一处又写日志']);
```

`log_push()` 还有一个特性是延迟执行(脚本程序结束时才真正写日志)，因此上面例子又可以写成：

```
log_push('test', ['这里写日志']);
log_push('test', ['另一处又写日志']);

svc_log()->setExtraData('user_id', 123);
```

手动刷写日志场景：

默认自动刷写，特殊场景(在 `register_shutdown_function()` 之前就调用了日志有关方法)，手动刷写可参考 `\JDI\Services\Router::dispatch` 里的用法

```
svc_log()->autoFlush(false); // 关闭自动刷写
svc_log()->flush(); // 手动刷写
```

自定义日志引擎，参考 `\JDI\Support\Svc::log` 使用 `\JDI\Services\Log::setFlushHandler` 的例子

#### `url()` 带协议和域名的完整URL

[](#url-带协议和域名的完整url)

- 当前域名URL：`url('path/to')`
- 其它域名URL：`url(['test', '/path/to'])`

#### `panic()` 直接抛出业务异常对象

[](#panic-直接抛出业务异常对象)

- `panic(10001000)` 等于 `throw new AppException('10001000')` 自动转为错误码对应的文本，参考翻译文件 lang\_zh\_CN.php
- `panic('foo')` 等于 `throw new AppException('foo')`
- `panic('foo', ['bar'])` 等于 `throw (new AppException('foo'))->setData(['bar'])`

`AppException` 异常属于业务逻辑，能够作为提示通过接口返回给用户看，而其它异常则不会(安全考虑)

#### `request_flash()`, `old()` 记住并使用上次的请求参数

[](#request_flash-old-记住并使用上次的请求参数)

- `request_flash()` 把本次请求的参数缓存起来
- `old(string $name = null, string $default = '')` 上次请求的字段值

#### `csrf_*()` CSRF

[](#csrf_-csrf)

- `csrf_field()`直接生成 HTML
- `csrf_token()`生成 token
- `csrf_check()`效验，token 来源于 `$_SERVER['HTTP_X_CSRF_TOKEN'], $_POST['_token'], $_GET['_token'], $_REQUEST['_token']`

请求时带上 `Token`, 使用以下任意一种方法

- `POST` 请求通过表单参数 `_token`, 后端将从 `$_POST['_token']` 读取
- `GET` 请求通过 `?_token=`, 后端将从 `$_GET['_token']` 读取
- 通过指定请求头 `X-CSRF-Token`, 后端将从 `$_SERVER['HTTP_X_CSRF_TOKEN']` 读取

#### `flash_*()` 闪存，一性次缓存

[](#flash_-闪存一性次缓存)

- `flash_set(string $key, $value)` 闪存设置
- `flash_has(string $key)` 存在且为真
- `flash_exists(string $key)` 闪存是否存在，即使值为 null
- `flash_get(string $key)` 闪存获取并删除
- `flash_del(string $key)` 闪存删除

#### `assign()`, `view()` 模板与变量

[](#assign-view-模板与变量)

- `assign('firstName', 'Hello')` 定义模板变量
- `return view('demo', ['title' => $title])` 定义模板变量的同时返回渲染内容

#### `back()`, `redirect()`, `alert()` 网页跳转

[](#back-redirect-alert-网页跳转)

- `back()` 网页后退
- `redirect('/demo')` 跳转到 `/demo`
- `alert()` JS alert() 并跳转回上一页

登录
--

[](#登录)

```
svc_auth()->login(1010); // 登录 ID 为 1010
svc_auth()->getUserId(); // 1010
svc_auth()->isLogin(); // true
svc_auth()->logout(); // 退出登录
```

消息队列
----

[](#消息队列)

- worker 遇到信号 `SIGTERM`, `SIGHUP`, `SIGINT`, `SIGQUIT` 会平滑结束进程。如果要强行结束可使用信号 `SIGKILL`, 命令为 `kill -s KILL `
- 当文件有变动时，队列有消息会触发 worker 退出，因此需要以守护进程方式启动 worker, 建议生产环境使用 supervisor 服务，临时测试可用 `watch` 命令启动 worker

### 依赖

[](#依赖)

`composer require php-amqplib/php-amqplib:^2.9`

### 配置

[](#配置)

`config/rabbitmq.php`

### 用例

[](#用例-1)

参考 `tests/feature/message_queue.php`

建议规则：

- 每个 worker 只消费一个队列；
- 队列名与 worker名 一致，便于定位队列名对应的 worker 文件；
- 队列名与 worker名 要有项目名前缀，防止在 Supervisor, RabbitMq 里与其它项目搞混

OPS 运维与开发
---------

[](#ops-运维与开发)

推荐使用本框架的运维后台 [jdi-ops](https://github.com/muzk6/jdi-ops)

### XDebug Trace

[](#xdebug-trace)

> 跟踪调试日志

日志默认位于 `data/xdebug_trace/`

#### 依赖

[](#依赖-1)

`ext-xdebug`

#### 跟踪 fpm

[](#跟踪-fpm)

- 当前URL 主动开启: `/?_xt=name0`，`name0`是当前日志的标识名
- Cookie 主动开启: `_xt=name0;`

*注意：`URL`, `Cookie` 方式的前提必须先设置 `config/whitelist.php` 白名单 `IP` 或 白名单 `Cookie`*

#### 跟踪 cli

[](#跟踪-cli)

`php demo.php --trace` 在任何脚本命令后面加上参数 `--trace` 即可

### XHProf

[](#xhprof)

日志默认位于 `data/xhprof/`

#### 依赖

[](#依赖-2)

[扩展 tideways\_xhprof](https://github.com/tideways/php-xhprof-extension/releases)

#### 使用

[](#使用)

- 配置文件 `config/xhprof.php`
- `enable` 设置为 `1`, 即可记录大于等于指定耗时的请求

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance56

Moderate activity, may be stable

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~38 days

Recently: every ~374 days

Total

42

Last Release

479d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/60f2728584dca3b6ff03b80c4e1ffcab653542c617e80f91fcf87301159011d4?d=identicon)[muzk6](/maintainers/muzk6)

---

Top Contributors

[![muzk6](https://avatars.githubusercontent.com/u/12749108?v=4)](https://github.com/muzk6 "muzk6 (93 commits)")

### Embed Badge

![Health badge](/badges/muzk6-jdi/health.svg)

```
[![Health](https://phpackages.com/badges/muzk6-jdi/health.svg)](https://phpackages.com/packages/muzk6-jdi)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
