Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions KnownIssues-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,15 @@ class TestController extends Controller
'enable' => true, // 启用自动销毁控制器
'excluded_list' => [
//\App\Http\Controllers\TestController::class, // 排除销毁的控制器类列表
//'App\Http\Controllers\V2\*', // 支持使用通配符的命名空间前缀匹配,该命名空间下的所有控制器都会被排除
],
],
```

有两种方式可以排除控制器不被销毁:
1. 精确匹配:指定完整的类名
2. 前缀匹配:在命名空间末尾使用通配符(*),例如 `App\Http\Controllers\V2\*` 将排除该命名空间下的所有控制器

## 不能使用这些函数

- `flush`/`ob_flush`/`ob_end_flush`/`ob_implicit_flush`:`swoole_http_response`不支持`flush`。
Expand Down
5 changes: 5 additions & 0 deletions KnownIssues.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,15 @@ class TestController extends Controller
'enable' => true, // Enable automatic destruction controller
'excluded_list' => [
//\App\Http\Controllers\TestController::class, // The excluded list of destroyed controller classes
//'App\Http\Controllers\V2\*', // Support namespace prefix with wildcard, all controllers under this namespace will be excluded
],
],
```

There are two ways to exclude controllers from being destroyed:
1. Exact match: specify the full class name
2. Prefix match: use wildcard (*) at the end of namespace, for example `App\Http\Controllers\V2\*` will exclude all controllers under this namespace

## Cannot call these functions

- `flush`/`ob_flush`/`ob_end_flush`/`ob_implicit_flush`: `swoole_http_response` does not support `flush`.
Expand Down
52 changes: 46 additions & 6 deletions src/Illuminate/CleanerManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ class CleanerManager

/**
* White list of controllers to be destroyed
* @var array
* @var array<string,bool>
*/
protected $whiteListControllers = [];

/**
* White list of controller prefixes to be excluded
* @var array<string,bool>
*/
protected $whiteListPrefixes = [];

/**
* @var array
*/
Expand Down Expand Up @@ -152,12 +158,45 @@ public function cleanProviders()
/**
* Register white list of controllers for cleaning.
*
* @param array providers
* @param array $controllers
*/
protected function registerCleanControllerWhiteList(array $controllers = [])
{
$controllers = array_unique($controllers);
$this->whiteListControllers = array_combine($controllers, $controllers);
$this->whiteListControllers = [];
$this->whiteListPrefixes = [];

foreach ($controllers as $controller) {
if (str_ends_with($controller, '*')) {
$prefix = substr($controller, 0, -1);
$this->whiteListPrefixes[$prefix] = true; // 使用关联数组
} else {
$this->whiteListControllers[$controller] = true; // 统一使用 true 作为值
}
}
}

/**
* Check if controller should be excluded from cleaning
*
* @param string $controllerClass
* @return bool
*/
protected function shouldExcludeController(string $controllerClass): bool
{
// 1. 精确匹配检查(O(1))
if (isset($this->whiteListControllers[$controllerClass])) {
return true;
}

// 2. 前缀匹配检查
// 使用关联数组后,可以优化前缀匹配的性能
foreach ($this->whiteListPrefixes as $prefix => $_) {
if (strncmp($controllerClass, $prefix, strlen($prefix)) === 0) {
return true;
}
}

return false;
}

/**
Expand All @@ -180,15 +219,16 @@ public function cleanControllers()
}

if (isset($route->controller)) { // For Laravel 5.4+
if (empty($this->whiteListControllers) || !isset($this->whiteListControllers[get_class($route->controller)])) {
if (!$this->shouldExcludeController(get_class($route->controller))) {
unset($route->controller);
}
} else {
$reflection = new \ReflectionClass(get_class($route));
if ($reflection->hasProperty('controller')) { // Laravel 5.3
$controller = $reflection->getProperty('controller');
$controller->setAccessible(true);
if (empty($this->whiteListControllers) || (($instance = $controller->getValue($route)) && !isset($this->whiteListControllers[get_class($instance)]))) {
$instance = $controller->getValue($route);
if ($instance && !$this->shouldExcludeController(get_class($instance))) {
$controller->setValue($route, null);
}
}
Expand Down