PHP code example of ysh / webman-annotation
1. Go to this page and download the library: Download ysh/webman-annotation library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
ysh / webman-annotation example snippets
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\GetMapping;
class IndexController
{
#[GetMapping('/')]
public function index()
{
return json(['message' => 'Hello Webman Annotation!']);
}
}
return [
// ========== 基础配置 ==========
// 是否启用注解功能
'enable' => true,
// 是否启用缓存(生产环境建议开启)
'enable_cache' => false,
// ========== 扫描配置 ==========
// 扫描目录(递归扫描子目录)
'scan_dirs' => [
app_path(),
],
// 排除目录(这些目录不会被扫描)
'exclude_dirs' => [
'vendor',
'runtime',
'config',
'public',
],
// ========== 自动注册配置 ==========
// 是否自动注册路由
'auto_register_routes' => true,
// 是否自动注册中间件
'auto_register_middleware' => true,
// 是否自动注册 Bean
'auto_register_beans' => true,
// 是否自动注册定时任务
'auto_register_crons' => true,
// 是否自动注册事件监听器
'auto_register_events' => true,
// 是否启用值注入
'enable_value_injection' => true,
// ========== 自定义注解配置 ==========
// 自定义注解映射(格式:'AnnotationClass' => 'HandlerClass')
'annotations' => [
// \app\annotation\MyAnnotation::class => \app\annotation\MyAnnotationHandler::class,
],
// ========== 黑名单配置 ==========
// 排除特定注解、类或命名空间(提高扫描性能)
'blacklist' => [
// 排除特定注解类(即使它们在白名单中)
'annotations' => [
// \Some\Package\UnwantedAnnotation::class,
],
// 排除特定类(不扫描这些类)
'classes' => [
// \app\legacy\OldController::class,
],
// 排除整个命名空间(该命名空间下的所有类都会被跳过)
'namespaces' => [
// 'app\legacy',
// 'app\deprecated',
],
],
// ========== 缓存配置 ==========
// 缓存存储名称(对应 config/cache.php 中的 stores,空值使用默认存储)
'cache_store' => '',
// 缓存键前缀
'cache_prefix' => 'annotation:',
// 缓存过期时间(秒),默认 24 小时
'cache_ttl' => 86400,
// ========== 日志配置 ==========
// 日志通道(对应 config/log.php 中的配置)
'log_channel' => 'default',
// ========== 定时任务监控配置 ==========
'cron_monitor' => [
// 是否启用定时任务监控进程
'enable' => true,
// 健康检查间隔(秒)
'check_interval' => 60,
// 是否启用自动恢复
'auto_recovery' => true,
// 最大连续失败次数
'max_failures' => 3,
],
// ========== Channel 配置 ==========
// webman/channel 配置(用于定时任务动态注册)
'channel' => [
'host' => '127.0.0.1',
'port' => 2206,
],
];
return [
'cron-monitor' => [
'handler' => \X2nx\WebmanAnnotation\Process\CronMonitor::class,
'count' => 1,
'reloadable' => false,
],
];
return [
'' => [
\X2nx\WebmanAnnotation\Middleware\AnnotationsMiddleware::class,
],
];
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\GetMapping;
use X2nx\WebmanAnnotation\Attributes\PostMapping;
use X2nx\WebmanAnnotation\Attributes\PutMapping;
use X2nx\WebmanAnnotation\Attributes\PatchMapping;
use X2nx\WebmanAnnotation\Attributes\DeleteMapping;
use X2nx\WebmanAnnotation\Attributes\OptionsMapping;
use X2nx\WebmanAnnotation\Attributes\TraceMapping;
use X2nx\WebmanAnnotation\Attributes\Route;
class UserController
{
// GET 请求
#[GetMapping('/users')]
public function list()
{
return json(['code' => 0, 'data' => []]);
}
// POST 请求
#[PostMapping('/users')]
public function create()
{
return json(['code' => 0, 'msg' => 'success']);
}
// PUT 请求
#[PutMapping('/users/{id}')]
public function update($id)
{
return json(['code' => 0, 'msg' => 'updated', 'id' => $id]);
}
// PATCH 请求
#[PatchMapping('/users/{id}')]
public function partialUpdate($id)
{
return json(['code' => 0, 'msg' => 'partially updated', 'id' => $id]);
}
// DELETE 请求
#[DeleteMapping('/users/{id}')]
public function delete($id)
{
return json(['code' => 0, 'msg' => 'deleted', 'id' => $id]);
}
// OPTIONS 请求(用于 CORS 预检)
#[OptionsMapping('/users/{id}')]
public function options($id)
{
return response('', 200)
->withHeaders([
'Access-Control-Allow-Methods' => 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
]);
}
// TRACE 请求(用于调试)
#[TraceMapping('/users/trace')]
public function trace()
{
return json(['method' => 'TRACE', 'message' => 'Trace request']);
}
// 使用 Route 注解(需要指定 HTTP 方法)
#[Route('GET', '/users/{id}')]
public function show($id)
{
return json(['code' => 0, 'data' => ['id' => $id]]);
}
// 支持多种 HTTP 方法(使用多个注解)
#[GetMapping('/users/{id}/info')]
#[PostMapping('/users/{id}/info')]
public function info($id)
{
return json(['code' => 0, 'data' => ['id' => $id]]);
}
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\RoutePrefix;
use X2nx\WebmanAnnotation\Attributes\RouteGroup; // RoutePrefix 的别名
use X2nx\WebmanAnnotation\Attributes\Controller; // 另一种写法
use X2nx\WebmanAnnotation\Attributes\GetMapping;
use X2nx\WebmanAnnotation\Attributes\PostMapping;
// 方式 1: 使用 RoutePrefix
#[RoutePrefix('/api/v1/user')]
class UserController
{
#[GetMapping('/list')] // 实际路径: /api/v1/user/list
public function list() { }
#[PostMapping('/create')] // 实际路径: /api/v1/user/create
public function create() { }
}
// 方式 2: 使用 RouteGroup(RoutePrefix 的别名)
#[RouteGroup('/api/v2/user')]
class UserV2Controller
{
#[GetMapping('/list')] // 实际路径: /api/v2/user/list
public function list() { }
}
// 方式 3: 使用 Controller
#[Controller(prefix: '/api/v3/user')]
class UserV3Controller
{
#[GetMapping('/list')] // 实际路径: /api/v3/user/list
public function list() { }
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\GetMapping;
use X2nx\WebmanAnnotation\Attributes\Route;
class UserController
{
// 为路由指定名称,便于反向生成 URL
#[GetMapping('/users/{id}', name: 'user.show')]
public function show($id)
{
return json(['id' => $id]);
}
// 使用 Route 注解也可以指定名称
#[Route('GET', '/users/{id}/edit', name: 'user.edit')]
public function edit($id)
{
return json(['id' => $id]);
}
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\GetMapping;
class UserController
{
// 路径参数
#[GetMapping('/users/{id}')]
public function show($id)
{
return json(['id' => $id]);
}
// 多个路径参数
#[GetMapping('/users/{userId}/posts/{postId}')]
public function showPost($userId, $postId)
{
return json(['user_id' => $userId, 'post_id' => $postId]);
}
// 可选参数(Webman 路由特性)
#[GetMapping('/users/{id?}')]
public function listOrShow($id = null)
{
if ($id) {
return json(['id' => $id]);
}
return json(['list' => []]);
}
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Middleware;
use X2nx\WebmanAnnotation\Attributes\GetMapping;
use app\middleware\AuthMiddleware;
use app\middleware\LogMiddleware;
// 类级别的中间件会应用到所有方法
#[Middleware([AuthMiddleware::class, LogMiddleware::class])]
class UserController
{
#[GetMapping('/profile')]
public function profile()
{
// 会先执行 AuthMiddleware 和 LogMiddleware
return json(['code' => 0, 'data' => []]);
}
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Middleware;
use X2nx\WebmanAnnotation\Attributes\GetMapping;
use app\middleware\AuthMiddleware;
use app\middleware\RateLimitMiddleware;
#[Middleware([AuthMiddleware::class])]
class UserController
{
// 方法级别的中间件会合并类级别的中间件
// 执行顺序:AuthMiddleware (类) -> RateLimitMiddleware (方法)
#[GetMapping('/profile')]
#[Middleware([RateLimitMiddleware::class])]
public function profile()
{
return json(['code' => 0, 'data' => []]);
}
// 只执行类级别的中间件
#[GetMapping('/info')]
public function info()
{
return json(['code' => 0, 'data' => []]);
}
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Middleware;
use X2nx\WebmanAnnotation\Attributes\PostMapping;
class OrderController
{
#[PostMapping('/orders')]
#[Middleware([
\app\middleware\AuthMiddleware::class,
\app\middleware\RateLimitMiddleware::class,
\app\middleware\ValidationMiddleware::class,
])]
public function create()
{
// 按顺序执行:AuthMiddleware -> RateLimitMiddleware -> ValidationMiddleware
return json(['code' => 0, 'msg' => 'success']);
}
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Value;
class IndexController
{
// 注入配置值
#[Value(key: 'app.name', default: 'MyApp')]
protected string $appName;
// 注入环境变量
#[Value(key: 'env:APP_DEBUG', default: false)]
protected bool $debug;
// 注入嵌套配置
#[Value(key: 'database.default.host', default: 'localhost')]
protected string $dbHost;
public function index()
{
return json([
'app_name' => $this->appName,
'debug' => $this->debug,
'db_host' => $this->dbHost,
]);
}
}
namespace app\service;
use X2nx\WebmanAnnotation\Attributes\Value;
class ConfigService
{
// 配置键(使用点号分隔)
#[Value(key: 'app.name')]
protected string $appName;
// 环境变量(使用 env: 前缀)
#[Value(key: 'env:APP_DEBUG')]
protected bool $debug;
// 数组配置
#[Value(key: 'database.default')]
protected array $database;
// 带默认值
#[Value(key: 'app.timezone', default: 'Asia/Shanghai')]
protected string $timezone;
// 环境变量带默认值
#[Value(key: 'env:APP_ENV', default: 'production')]
protected string $env;
}
namespace app\service;
use X2nx\WebmanAnnotation\Attributes\Value;
class ConfigService
{
// 自动类型转换
#[Value(key: 'app.port', default: 8080)]
protected int $port; // 自动转换为 int
#[Value(key: 'app.debug', default: false)]
protected bool $debug; // 自动转换为 bool
#[Value(key: 'app.allowed_hosts', default: [])]
protected array $allowedHosts; // 自动转换为 array
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Inject;
use app\service\UserService;
class UserController
{
// 通过类型提示自动注入
#[Inject]
protected UserService $userService;
public function index()
{
$users = $this->userService->getAll();
return json(['code' => 0, 'data' => $users]);
}
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Inject;
class UserController
{
// 通过名称注入(从容器中获取名为 'userService' 的服务)
#[Inject(name: 'userService')]
protected $userService;
// 也可以指定类型
#[Inject(name: 'logger')]
protected \Psr\Log\LoggerInterface $logger;
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Inject;
use app\service\HeavyService;
class UserController
{
// 懒加载:只有在第一次访问时才创建实例
#[Inject(lazy: true)]
protected HeavyService $heavyService;
public function index()
{
// 此时 heavyService 还没有被创建
// ...
// 第一次访问时才会创建实例
$result = $this->heavyService->process();
return json(['code' => 0, 'data' => $result]);
}
}
namespace app\service;
use X2nx\WebmanAnnotation\Attributes\Inject;
// ServiceA 依赖 ServiceB
class ServiceA
{
#[Inject]
protected ServiceB $serviceB;
public function getName(): string
{
return 'ServiceA';
}
public function getServiceB(): ServiceB
{
return $this->serviceB;
}
}
// ServiceB 依赖 ServiceA(循环依赖)
class ServiceB
{
#[Inject]
protected ServiceA $serviceA;
public function getName(): string
{
return 'ServiceB';
}
public function getServiceA(): ServiceA
{
return $this->serviceA;
}
}
// 在控制器中使用
class UserController
{
#[Inject]
protected ServiceA $serviceA;
public function index()
{
// 循环依赖已自动处理,可以直接使用
$serviceB = $this->serviceA->getServiceB();
$serviceA = $serviceB->getServiceA();
// $serviceA === $this->serviceA (true)
return json(['success' => true]);
}
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Inject;
use X2nx\WebmanAnnotation\Attributes\Value;
use app\service\UserService;
class UserController
{
// 同时使用 Value 和 Inject
#[Value(key: 'app.name')]
protected string $appName;
#[Inject]
protected UserService $userService;
#[Value(key: 'env:APP_DEBUG', default: false)]
protected bool $debug;
public function index()
{
return json([
'app_name' => $this->appName,
'users' => $this->userService->getAll(),
'debug' => $this->debug,
]);
}
}
namespace app\service;
use X2nx\WebmanAnnotation\Attributes\Bean;
// 注册为单例,使用类名作为服务名
#[Bean]
class UserService
{
public function getAll()
{
return ['user1', 'user2'];
}
}
// 在其他地方使用
use support\Container;
$userService = Container::get(\app\service\UserService::class);
$users = $userService->getAll();
namespace app\service;
use X2nx\WebmanAnnotation\Attributes\Bean;
// 注册为命名 Bean
#[Bean('userService')]
class UserService
{
public function getAll()
{
return ['user1', 'user2'];
}
}
// 在其他地方使用
use support\Container;
$userService = Container::get('userService');
$users = $userService->getAll();
namespace app\service;
use X2nx\WebmanAnnotation\Attributes\Bean;
use X2nx\WebmanAnnotation\Attributes\Inject;
use X2nx\WebmanAnnotation\Attributes\Value;
#[Bean('orderService')]
class OrderService
{
#[Value(key: 'app.name')]
protected string $appName;
#[Inject]
protected UserService $userService;
public function createOrder()
{
// 可以使用注入的依赖
$users = $this->userService->getAll();
return ['order' => 'created', 'app' => $this->appName];
}
}
namespace app\task;
use X2nx\WebmanAnnotation\Attributes\Cron;
use X2nx\WebmanAnnotation\Attributes\Value;
class CleanupTask
{
#[Value(key: 'app.name')]
protected string $appName;
/**
* 每5秒执行一次(每次创建新实例)
*/
#[Cron(expression: '*/5 * * * * *', singleton: false)]
public function cleanup()
{
echo "[{$this->appName}] Cleanup task executed at " . date('Y-m-d H:i:s') . "\n";
// 执行清理逻辑
}
/**
* 每天凌晨2点执行(使用单例模式)
*/
#[Cron(expression: '0 2 * * *', singleton: true)]
public function dailyReport()
{
echo "Daily report generated\n";
}
}
// 每5秒执行
#[Cron(expression: '*/5 * * * * *')]
// 每10分钟执行
#[Cron(expression: '0 */10 * * * *')]
// 每小时执行
#[Cron(expression: '0 0 * * * *')]
// 每天凌晨2点执行
#[Cron(expression: '0 0 2 * * *')]
// 每周一凌晨3点执行
#[Cron(expression: '0 0 3 * * 1')]
// 每月1号凌晨4点执行
#[Cron(expression: '0 0 4 1 * *')]
// 工作日上午9点执行
#[Cron(expression: '0 0 9 * * 1-5')]
#[Cron(
expression: '*/5 * * * * *', // Cron 表达式(必填)
singleton: true // 是否使用单例模式(默认:true)
)]
namespace app\task;
use X2nx\WebmanAnnotation\Attributes\Cron;
use X2nx\WebmanAnnotation\Attributes\Value;
use X2nx\WebmanAnnotation\Attributes\Inject;
use app\service\UserService;
class ReportTask
{
#[Value(key: 'app.name')]
protected string $appName;
#[Inject]
protected UserService $userService;
#[Cron(expression: '0 0 * * * *')]
public function hourlyReport()
{
$users = $this->userService->getAll();
echo "[{$this->appName}] Hourly report: " . count($users) . " users\n";
}
}
use X2nx\WebmanAnnotation\Helper\CronHelper;
// 注册类方法
$taskId = CronHelper::register(
expression: '*/10 * * * * *',
class: \app\task\MyTask::class,
method: 'execute',
name: 'MyTask::execute',
singleton: true,
multiProcess: false
);
// 注册回调函数
$taskId = CronHelper::registerCallable(
expression: '0 * * * * *',
callback: function() {
echo "Task executed\n";
},
name: 'my-callback-task'
);
// 取消注册
CronHelper::unregister($taskId);
// 获取所有任务
$tasks = CronHelper::getAll();
namespace app\listener;
use X2nx\WebmanAnnotation\Attributes\Event;
class UserListener
{
// 监听 user.created 事件
#[Event('user.created')]
public function handleUserCreated($user)
{
// 处理用户创建事件
echo "User created: {$user['name']}\n";
}
// 监听 user.updated 事件,设置优先级
#[Event('user.updated', priority: 10)]
public function handleUserUpdated($user)
{
// 处理用户更新事件(优先级 10,数字越小优先级越高)
echo "User updated: {$user['name']}\n";
}
}
use Webman\Event\Event;
// 触发事件
Event::emit('user.created', ['name' => 'John', 'email' => '[email protected] ']);
// 或者使用 dispatch(如果支持)
Event::dispatch('user.updated', ['name' => 'Jane', 'email' => '[email protected] ']);
namespace app\listener;
use X2nx\WebmanAnnotation\Attributes\Event;
class LogListener
{
// 一个方法可以监听多个事件
#[Event('user.created')]
#[Event('user.updated')]
#[Event('user.deleted')]
public function handleUserEvents($data, $eventName)
{
// $data 是事件数据
// $eventName 是事件名称
echo "Event {$eventName} triggered with data: " . json_encode($data) . "\n";
}
}
namespace app\listener;
use X2nx\WebmanAnnotation\Attributes\Event;
class UserListener
{
// 优先级 1(最高优先级,最先执行)
#[Event('user.created', priority: 1)]
public function validateUser($user)
{
// 验证用户数据
}
// 优先级 10(较低优先级,后执行)
#[Event('user.created', priority: 10)]
public function sendWelcomeEmail($user)
{
// 发送欢迎邮件
}
// 无优先级(默认优先级)
#[Event('user.created')]
public function logUserCreation($user)
{
// 记录日志
}
}
namespace app\listener;
use X2nx\WebmanAnnotation\Attributes\Event;
use X2nx\WebmanAnnotation\Attributes\Value;
use X2nx\WebmanAnnotation\Attributes\Inject;
use app\service\EmailService;
class UserListener
{
#[Value(key: 'app.name')]
protected string $appName;
#[Inject]
protected EmailService $emailService;
#[Event('user.created')]
public function handleUserCreated($user)
{
// 可以使用注入的依赖
$this->emailService->send(
$user['email'],
"Welcome to {$this->appName}!"
);
}
}
namespace app\annotation;
use Attribute;
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]
class Cache
{
public function __construct(
public int $ttl = 3600,
public string $key = ''
) {
}
}
namespace app\annotation;
use X2nx\WebmanAnnotation\Contracts\AnnotationsHandlerInterface;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
class CacheHandler implements AnnotationsHandlerInterface
{
public function handle(
object $attribute,
ReflectionClass $class,
?ReflectionMethod $method,
?ReflectionProperty $property
): void {
// 处理注解逻辑
if ($method) {
echo "Cache annotation on method: {$class->getName()}::{$method->getName()}\n";
echo "TTL: {$attribute->ttl}, Key: {$attribute->key}\n";
} elseif ($class) {
echo "Cache annotation on class: {$class->getName()}\n";
}
}
}
return [
'annotations' => [
\app\annotation\Cache::class => \app\annotation\CacheHandler::class,
],
];
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\GetMapping;
use app\annotation\Cache;
class UserController
{
// 在方法上使用自定义注解
#[GetMapping('/users')]
#[Cache(ttl: 3600, key: 'users:list')]
public function list()
{
return json(['code' => 0, 'data' => []]);
}
}
use X2nx\WebmanAnnotation\Helper\AnnotationsExecutor;
// 执行类上的所有自定义注解
$result = AnnotationsExecutor::executeClass(\app\controller\UserController::class);
// 执行方法上的自定义注解
$result = AnnotationsExecutor::executeMethod(\app\controller\UserController::class, 'list');
// 执行属性上的自定义注解
$result = AnnotationsExecutor::executeProperty(\app\controller\UserController::class, 'userService');
// 检查执行结果
if ($result['success']) {
echo "成功执行了 {$result['handled']} 个自定义注解\n";
} else {
echo "执行失败: " . implode(', ', $result['errors']) . "\n";
}
return [
'blacklist' => [
// 排除特定注解类(即使它们在白名单中)
'annotations' => [
\Some\Package\UnwantedAnnotation::class,
],
// 排除特定类(不扫描这些类)
'classes' => [
\app\legacy\OldController::class,
],
// 排除整个命名空间
'namespaces' => [
'app\legacy',
'app\deprecated',
],
],
];
return [
// 启用缓存(生产环境建议开启)
'enable_cache' => true,
// 缓存配置
'cache_store' => 'redis', // 使用 Redis 缓存
'cache_prefix' => 'annotation:',
'cache_ttl' => 86400, // 24 小时
];
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Inject;
use app\service\HeavyService;
class UserController
{
// 懒加载:只有在第一次访问时才创建实例
#[Inject(lazy: true)]
protected HeavyService $heavyService;
public function index()
{
// 第一次访问时才会创建实例
return $this->heavyService->process();
}
}
use X2nx\WebmanAnnotation\Helper\CronHelper;
// 在运行时动态注册任务
$taskId = CronHelper::register(
expression: '*/30 * * * * *',
class: \app\task\DynamicTask::class,
method: 'execute',
name: 'DynamicTask',
singleton: true,
multiProcess: false
);
// 取消注册
CronHelper::unregister($taskId);
namespace app\controller\api\v1;
use X2nx\WebmanAnnotation\Attributes\RoutePrefix;
use X2nx\WebmanAnnotation\Attributes\GetMapping;
use X2nx\WebmanAnnotation\Attributes\PostMapping;
#[RoutePrefix('/api/v1/users')]
class UserController
{
#[GetMapping('')]
public function list() { }
#[PostMapping('')]
public function create() { }
#[GetMapping('/{id}')]
public function show($id) { }
}
namespace app\controller;
use X2nx\WebmanAnnotation\Attributes\Inject;
use X2nx\WebmanAnnotation\Attributes\Value;
use app\service\UserService;
class UserController
{
// 使用类型提示注入(推荐)
#[Inject]
protected UserService $userService;
// 配置值注入
#[Value(key: 'app.name')]
protected string $appName;
}
namespace app\task;
use X2nx\WebmanAnnotation\Attributes\Cron;
class CleanupTask
{
// 使用单例模式,减少内存占用
#[Cron(expression: '0 2 * * *', singleton: true)]
public function dailyCleanup()
{
// 清理逻辑
}
// 高频任务使用多进程执行
#[Cron(expression: '*/5 * * * * *', singleton: false, multiProcess: true)]
public function frequentTask()
{
// 高频任务逻辑
}
}
namespace app\listener;
use X2nx\WebmanAnnotation\Attributes\Event;
class UserListener
{
// 使用优先级控制执行顺序
#[Event('user.created', priority: 1)]
public function validate($user) { }
#[Event('user.created', priority: 10)]
public function sendEmail($user) { }
}
// config/plugin/x2nx/webman-annotation/app.php
return [
// 生产环境启用缓存
'enable_cache' => true,
'cache_store' => 'redis',
// 配置黑名单,排除不需要扫描的类
'blacklist' => [
'namespaces' => [
'app\legacy',
'app\deprecated',
],
],
];
bash
php start.php restart