跳转到主要内容

什么是 Manager

Illuminate\Support\Manager 是从 Laravel 4.0 时代就存在的抽象类。它为缓存、Session、Mail 等能切换多个「驱动」的系统提供了简洁的构建基础。 「驱动」是指具有相同接口但内部实现不同的后端。例如 Session 有 filecookiedatabaseredis 等驱动,可通过配置文件的 driver 键切换。

框架内的使用情况

Manager 命名的类并非都继承自 Illuminate\Support\Manager
是否继承 Manager
Illuminate\Session\SessionManager✅ 继承
Illuminate\Cache\CacheManager❌ 未继承(自实现)
Illuminate\Queue\QueueManager❌ 未继承(自实现)
Laravel\Socialite\SocialiteManager✅ 继承
即使未继承,用 extend() 扩展的基本思路也一致。因此理解 Manager 模式有助于把握整个框架的运作。

基本机制

driver() — 获取驱动

调用 driver() 后,驱动按下面的流程解析: 查看实际源码可以看到,它是用 Str::studly() 将驱动名拼出方法名。
// 摘自 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(),可以注册自定义驱动。闭包参数是容器实例。
use Illuminate\Support\Facades\Session;

Session::extend('redis-cluster', function ($app) {
    return new RedisClusterSessionHandler(
        $app->make('redis'),
        $app['config']['session'],
    );
});
extend() 会把闭包绑定到 $this,因此在闭包中可以访问 Manager 的属性与方法。
// 摘自 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 本身不存在的方法调用会自动委托给默认驱动。
public function __call($method, $parameters)
{
    return $this->driver()->$method(...$parameters);
}
因此可以像 SessionManager::get('key') 一样直接使用 Manager,实际处理则交给驱动。

SessionManager 实现示例

看看 Illuminate\Session\SessionManager,可以具体了解 Manager 的用法。
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 的类。
1

创建继承 Manager 的类

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'),
        );
    }
}
2

在 Service Provider 中注册

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);
        });
    }
}
3

添加自定义驱动

// 例如在 AppServiceProvider::boot() 中

$manager = app(NotificationManager::class);

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

使用

$manager = app(NotificationManager::class);

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

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

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

MultipleInstanceManager

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

与 Manager 的区别

ManagerMultipleInstanceManager
管理单元驱动种类(如 fileredis具名实例(如 mailer1mailer2
配置方式一个默认驱动每个实例都有独立配置
典型用途Session、Cache 等Mail、Log 等需要多连接的场景
获取方法driver()instance()

必需方法

继承 MultipleInstanceManager 时需要实现 3 个方法。
// 摘自源码
abstract public function getDefaultInstance();
abstract public function setDefaultInstance($name);
abstract public function getInstanceConfig($name);
getInstanceConfig() 返回对应名字的配置数组。配置中必须包含 driver(或 $driverKey 指定的键)。

解析流程

自定义包的实现示例

以同时对接多个 SMS 网关的包为例。
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'],
        );
    }
}
对应的配置文件:
// 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() 指定名字。
$sms = app(SmsManager::class);

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

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

// 使用营销实例
$sms->instance('marketing')->send('+8613800000000', '活动通知');
MultipleInstanceManagerManager 一样支持通过 extend() 添加自定义驱动。它同样实现了 __call,实例本身不存在的方法会委托给默认实例。

驱动缓存管理

Manager 的缓存操作

// 获取全部驱动
$drivers = $manager->getDrivers();

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

MultipleInstanceManager 的缓存操作

// 移除特定实例
$manager->forgetInstance('backup');

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

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

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

小结

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

Macroable trait

学习向既有类添加自定义方法的 Macroable trait。
最后修改于 2026年7月13日