> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Illuminate\Support\Manager — 驱动系统剖析

> 自 Laravel 4.0 沿用至今的驱动系统核心类。从自定义驱动的注册到 MultipleInstanceManager 的完整讲解。

## 什么是 Manager

`Illuminate\Support\Manager` 是从 Laravel 4.0 时代就存在的抽象类。它为缓存、Session、Mail 等能切换多个「驱动」的系统提供了简洁的构建基础。

「驱动」是指具有相同接口但内部实现不同的后端。例如 Session 有 `file`、`cookie`、`database`、`redis` 等驱动，可通过配置文件的 `driver` 键切换。

```mermaid theme={null}
classDiagram
    class Manager {
        <<abstract>>
        #container
        #config
        #customCreators[]
        #drivers[]
        +driver(name) mixed
        +extend(driver, Closure) self
        +getDrivers() array
        +forgetDrivers() self
        +getDefaultDriver()* string
        #createDriver(driver) mixed
        #callCustomCreator(driver) mixed
    }

    class SessionManager {
        +getDefaultDriver() string
        #createFileDriver() Store
        #createDatabaseDriver() Store
        #createRedisDriver() Store
        #createArrayDriver() Store
    }

    class YourCustomManager {
        +getDefaultDriver() string
        #createFooDriver() mixed
        #createBarDriver() mixed
    }

    Manager <|-- SessionManager
    Manager <|-- YourCustomManager
```

## 框架内的使用情况

以 `Manager` 命名的类**并非**都继承自 `Illuminate\Support\Manager`。

| 类                                    | 是否继承 `Manager` |
| ------------------------------------ | -------------- |
| `Illuminate\Session\SessionManager`  | ✅ 继承           |
| `Illuminate\Cache\CacheManager`      | ❌ 未继承（自实现）     |
| `Illuminate\Queue\QueueManager`      | ❌ 未继承（自实现）     |
| `Laravel\Socialite\SocialiteManager` | ✅ 继承           |

即使未继承，用 `extend()` 扩展的基本思路也一致。因此理解 `Manager` 模式有助于把握整个框架的运作。

## 基本机制

### driver() — 获取驱动

调用 `driver()` 后，驱动按下面的流程解析：

```mermaid theme={null}
flowchart TD
    A["调用 driver(name)"] --> B{drivers[] 中<br>是否有缓存?}
    B -- 是 --> C["返回缓存的<br>实例"]
    B -- 否 --> D{customCreators[]<br>中是否注册?}
    D -- 是 --> E["用 callCustomCreator()<br>生成实例"]
    D -- 否 --> F{"createXxxDriver()<br>方法是否存在?"}
    F -- 是 --> G["调用 createXxxDriver()"]
    F -- 否 --> H["抛出 InvalidArgumentException"]
    E --> I["写入 drivers[] 缓存后返回"]
    G --> I
```

查看实际源码可以看到，它是用 `Str::studly()` 将驱动名拼出方法名。

```php theme={null}
// 摘自 Illuminate\Support\Manager::createDriver()
protected function createDriver($driver)
{
    if (isset($this->customCreators[$driver])) {
        return $this->callCustomCreator($driver);
    }

    $method = 'create'.Str::studly($driver).'Driver';

    if (method_exists($this, $method)) {
        return $this->$method();
    }

    throw new InvalidArgumentException("Driver [$driver] not supported.");
}
```

即 `file` 驱动调用 `createFileDriver()`，`my-custom` 驱动则调用 `createMyCustomDriver()`。

### extend() — 注册自定义驱动

将驱动名与闭包传给 `extend()`，可以注册自定义驱动。闭包参数是容器实例。

```php theme={null}
use Illuminate\Support\Facades\Session;

Session::extend('redis-cluster', function ($app) {
    return new RedisClusterSessionHandler(
        $app->make('redis'),
        $app['config']['session'],
    );
});
```

`extend()` 会把闭包绑定到 `$this`，因此在闭包中可以访问 Manager 的属性与方法。

```php theme={null}
// 摘自 Illuminate\Support\Manager::extend()
public function extend($driver, Closure $callback)
{
    try {
        $callback = $callback->bindTo($this, static::class) ?? throw new RuntimeException;
    } catch (Throwable) {
        $callback = $callback->bindTo(null, static::class);
    }

    $this->customCreators[$driver] = $callback;

    return $this;
}
```

### \_\_call — 委托到默认驱动

Manager 类实现了 `__call`，Manager 本身不存在的方法调用会自动委托给默认驱动。

```php theme={null}
public function __call($method, $parameters)
{
    return $this->driver()->$method(...$parameters);
}
```

因此可以像 `SessionManager::get('key')` 一样直接使用 Manager，实际处理则交给驱动。

## SessionManager 实现示例

看看 `Illuminate\Session\SessionManager`，可以具体了解 `Manager` 的用法。

```php theme={null}
namespace Illuminate\Session;

use Illuminate\Support\Manager;

class SessionManager extends Manager
{
    // 必需：返回默认驱动
    public function getDefaultDriver()
    {
        return $this->config->get('session.driver');
    }

    // file 驱动
    protected function createFileDriver()
    {
        return $this->createNativeDriver();
    }

    // database 驱动
    protected function createDatabaseDriver()
    {
        $table = $this->config->get('session.table');
        $lifetime = $this->config->get('session.lifetime');

        return $this->buildSession(new DatabaseSessionHandler(
            $this->getDatabaseConnection(), $table, $lifetime, $this->container
        ));
    }

    // redis 驱动
    protected function createRedisDriver()
    {
        $handler = $this->createCacheHandler('redis');
        // ...
        return $this->buildSession($handler);
    }
}
```

## 在自定义包中使用 Manager

### 基本实现

以通知服务为例，构建一个继承 `Manager` 的类。

<Steps>
  <Step title="创建继承 Manager 的类">
    ```php theme={null}
    namespace App\Notifications;

    use Illuminate\Support\Manager;

    class NotificationManager extends Manager
    {
        public function getDefaultDriver(): string
        {
            return $this->config->get('notifications.driver', 'slack');
        }

        protected function createSlackDriver(): SlackNotifier
        {
            return new SlackNotifier(
                $this->config->get('notifications.slack'),
            );
        }

        protected function createEmailDriver(): EmailNotifier
        {
            return new EmailNotifier(
                $this->config->get('notifications.email'),
            );
        }

        protected function createLogDriver(): LogNotifier
        {
            return new LogNotifier(
                $this->container->make('log'),
            );
        }
    }
    ```
  </Step>

  <Step title="在 Service Provider 中注册">
    ```php theme={null}
    namespace App\Providers;

    use App\Notifications\NotificationManager;
    use Illuminate\Support\ServiceProvider;

    class NotificationServiceProvider extends ServiceProvider
    {
        public function register(): void
        {
            $this->app->singleton(NotificationManager::class, function ($app) {
                return new NotificationManager($app);
            });
        }
    }
    ```
  </Step>

  <Step title="添加自定义驱动">
    ```php theme={null}
    // 例如在 AppServiceProvider::boot() 中

    $manager = app(NotificationManager::class);

    $manager->extend('teams', function ($app) {
        return new TeamsNotifier(
            $app['config']['notifications.teams'],
        );
    });
    ```
  </Step>

  <Step title="使用">
    ```php theme={null}
    $manager = app(NotificationManager::class);

    // 使用默认驱动
    $manager->send('消息');

    // 指定具体驱动
    $manager->driver('email')->send('消息');

    // 一次解析后的驱动会被缓存
    $manager->driver('slack'); // 返回相同实例
    ```
  </Step>
</Steps>

## MultipleInstanceManager

`Illuminate\Support\MultipleInstanceManager` 是 Laravel 10 中新增的类。`Manager` 管理的是「驱动种类」，而 `MultipleInstanceManager` 可以管理多个具名的「实例」。

### 与 Manager 的区别

|      | `Manager`              | `MultipleInstanceManager`   |
| ---- | ---------------------- | --------------------------- |
| 管理单元 | 驱动种类（如 `file`、`redis`） | 具名实例（如 `mailer1`、`mailer2`） |
| 配置方式 | 一个默认驱动                 | 每个实例都有独立配置                  |
| 典型用途 | Session、Cache 等        | Mail、Log 等需要多连接的场景          |
| 获取方法 | `driver()`             | `instance()`                |

### 必需方法

继承 `MultipleInstanceManager` 时需要实现 3 个方法。

```php theme={null}
// 摘自源码
abstract public function getDefaultInstance();
abstract public function setDefaultInstance($name);
abstract public function getInstanceConfig($name);
```

`getInstanceConfig()` 返回对应名字的配置数组。配置中必须包含 `driver`（或 `$driverKey` 指定的键）。

### 解析流程

```mermaid theme={null}
flowchart TD
    A["调用 instance(name)"] --> B["name 为 null 时<br>使用 getDefaultInstance()"]
    B --> C{instances[] 中<br>是否有缓存?}
    C -- 是 --> D["返回缓存的<br>实例"]
    C -- 否 --> E["通过 getInstanceConfig(name) 取配置"]
    E --> F{配置中是否<br>有 driver 键?}
    F -- 否 --> G["抛出 RuntimeException"]
    F -- 是 --> H{customCreators[]<br>是否有注册?}
    H -- 是 --> I["用 callCustomCreator(config) 生成"]
    H -- 否 --> J["调用 createXxxDriver(config)"]
    I --> K["写入 instances[] 缓存后返回"]
    J --> K
```

### 自定义包的实现示例

以同时对接多个 SMS 网关的包为例。

```php theme={null}
namespace App\Sms;

use Illuminate\Support\MultipleInstanceManager;

class SmsManager extends MultipleInstanceManager
{
    // 默认实例名
    public function getDefaultInstance(): string
    {
        return $this->config->get('sms.default', 'primary');
    }

    public function setDefaultInstance($name): void
    {
        $this->config->set('sms.default', $name);
    }

    // 返回实例名对应的配置
    public function getInstanceConfig($name): array
    {
        return $this->config->get("sms.gateways.{$name}");
    }

    // twilio 驱动（会传入配置数组）
    protected function createTwilioDriver(array $config): TwilioSmsGateway
    {
        return new TwilioSmsGateway(
            $config['account_sid'],
            $config['auth_token'],
        );
    }

    // vonage 驱动
    protected function createVonageDriver(array $config): VonageSmsGateway
    {
        return new VonageSmsGateway(
            $config['api_key'],
            $config['api_secret'],
        );
    }
}
```

对应的配置文件：

```php theme={null}
// config/sms.php
return [
    'default' => 'primary',

    'gateways' => [
        'primary' => [
            'driver' => 'twilio',
            'account_sid' => env('TWILIO_ACCOUNT_SID'),
            'auth_token' => env('TWILIO_AUTH_TOKEN'),
        ],
        'backup' => [
            'driver' => 'vonage',
            'api_key' => env('VONAGE_API_KEY'),
            'api_secret' => env('VONAGE_API_SECRET'),
        ],
        'marketing' => [
            'driver' => 'twilio',
            'account_sid' => env('TWILIO_MARKETING_SID'),
            'auth_token' => env('TWILIO_MARKETING_TOKEN'),
        ],
    ],
];
```

使用时通过 `instance()` 指定名字。

```php theme={null}
$sms = app(SmsManager::class);

// 使用默认实例（primary = twilio）
$sms->send('+8613800000000', '验证码：123456');

// 按名称使用指定实例
$sms->instance('backup')->send('+8613800000000', '验证码：123456');

// 使用营销实例
$sms->instance('marketing')->send('+8613800000000', '活动通知');
```

<Tip>
  `MultipleInstanceManager` 与 `Manager` 一样支持通过 `extend()` 添加自定义驱动。它同样实现了 `__call`，实例本身不存在的方法会委托给默认实例。
</Tip>

## 驱动缓存管理

### Manager 的缓存操作

```php theme={null}
// 获取全部驱动
$drivers = $manager->getDrivers();

// 清除全部驱动缓存
$manager->forgetDrivers();
```

### MultipleInstanceManager 的缓存操作

```php theme={null}
// 移除特定实例
$manager->forgetInstance('backup');

// 移除默认实例
$manager->forgetInstance();

// 一次移除多个实例
$manager->forgetInstance(['primary', 'backup']);

// 同时清除底层缓存
$manager->purge('backup');
```

## 小结

* `Manager` 管理驱动的「种类」。实现 `createXxxDriver()` 方法，用 `extend()` 扩展
* `MultipleInstanceManager` 按名字管理驱动的「实例」，适合需要多连接配置的包
* 名字里带 `Manager` 的类并不一定都继承自 `Illuminate\Support\Manager`。`CacheManager` 和 `QueueManager` 都是自实现

<Card title="Macroable trait" icon="puzzle-piece" href="/zh/advanced/macroable">
  学习向既有类添加自定义方法的 Macroable trait。
</Card>


## Related topics

- [Laravel Socialite（社交登录）](/zh/socialite.md)
- [Laravel Sentinel — 路由保护中间件调查](/zh/blog/sentinel-introduction.md)
- [文件存储](/zh/filesystem.md)
- [实现自定义认证 Guard](/zh/advanced/custom-auth-guard.md)
- [日志](/zh/logging.md)
