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

# パッケージ設定のマージとキャッシュ

> Laravel 13のServiceProvider実装から、浅いマージと再帰的な置換の違い、数値キー配列の落とし穴、設定キャッシュを考慮したパッケージの保守方法を解説します。

パッケージの設定を追加しても、利用者が以前に公開した設定ファイルには新しい項目が自動で書き込まれるわけではありません。公開済みの設定を壊さずにデフォルト値を補うには、配列のマージ方針と設定キャッシュの両方を設計する必要があります。

このページではLaravel 13の `ServiceProvider` を読み、設定をパッケージの公開APIとして保守する方法を整理します。[パッケージ開発の基礎](/jp/advanced/package-development)を前提とし、実装の確認には `laravel/framework` の `v13.34.0` を使用しています。

## 公開とマージは別の処理

`publishes()` はコピー元とコピー先を登録します。`vendor:publish` がファイルをコピーするまで、利用者の `config` ディレクトリは変わりません。一方、`mergeConfigFrom()` は起動時の設定リポジトリを更新し、ファイル自体を書き換えません。

```php theme={null}
<?php

namespace Acme\Courier;

use Illuminate\Support\ServiceProvider;

class CourierServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->mergeConfigFrom(
            __DIR__.'/../config/courier.php', 'courier'
        );
    }

    public function boot(): void
    {
        $this->publishes([
            __DIR__.'/../config/courier.php' => config_path('courier.php'),
        ], 'courier-config');
    }
}
```

利用者は必要なときだけ設定ファイルを公開します。公開しなくても、キャッシュがない通常の起動では `register()` のマージでデフォルト値が使われます。

```bash theme={null}
php artisan vendor:publish --tag=courier-config
```

<Warning>
  更新手順として設定ファイルを `--force` で再公開すると、利用者の編集内容を上書きします。新しい設定項目を追加するだけなら、デフォルト値の補完と変更点の案内を優先してください。
</Warning>

## mergeConfigFrom()は最上位だけをマージする

`ServiceProvider::mergeConfigFrom()` は、パッケージの設定を先に、アプリケーションの既存設定を後に渡して `array_merge()` を実行します。同じ文字列キーでは、アプリケーション側の値が優先されます。

以下はフレームワークのマージ処理を配列だけで再現した例です。

```php theme={null}
<?php

$defaults = [
    'enabled' => true,
    'transport' => [
        'timeout' => 10,
        'retries' => 3,
    ],
];

$overrides = [
    'transport' => [
        'timeout' => 30,
    ],
];

$config = array_merge($defaults, $overrides);

var_export($config);
```

```text theme={null}
array (
  'enabled' => true,
  'transport' =>
  array (
    'timeout' => 30,
  ),
)
```

最上位の `enabled` は補われますが、`transport` は配列全体が置き換わります。`transport.retries` は残りません。利用者が古い `transport` 配列を公開済みなら、新しいキーを同じ配列に追加しても補完されない点が重要です。

## replaceConfigRecursivelyFrom()でネストした設定を補う

Laravel 13の `ServiceProvider` には、protectedメソッドの `replaceConfigRecursivelyFrom()` もあります。こちらは同じ順序で `array_replace_recursive()` を実行します。

ネストした文字列キーを個別に上書きする設定APIにしたい場合は、プロバイダーの `register()` を次のように変更します。同じ設定キーに対して、先ほどの `mergeConfigFrom()` と併用する必要はありません。

```php theme={null}
public function register(): void
{
    $this->replaceConfigRecursivelyFrom(
        __DIR__.'/../config/courier.php', 'courier'
    );
}
```

先ほどの `$defaults` と `$overrides` を使うと、結果は次のようになります。

```php theme={null}
$config = array_replace_recursive($defaults, $overrides);

var_export($config);
```

```text theme={null}
array (
  'enabled' => true,
  'transport' =>
  array (
    'timeout' => 30,
    'retries' => 3,
  ),
)
```

| 設定の契約 | 選ぶ処理 | 注意点 |
| - | - | - |
| ネストした配列は利用者が全体を指定する | `mergeConfigFrom()` | 配列内の未指定キーは補われない |
| ネストした項目は利用者が一部だけ指定する | `replaceConfigRecursivelyFrom()` | 数値キーのリストも再帰的な置換の対象になる |

<Info>
  `replaceConfigRecursivelyFrom()` は、このページで確認したLaravel 13のソースコードに存在するメソッドです。公式のパッケージ開発ドキュメントが紹介する `mergeConfigFrom()` と区別し、対応するフレームワークの実装を確認して利用してください。
</Info>

### 数値キーのリストは全体置換にならない

再帰的な置換は「配列をすべて利用者の値に差し替える」処理ではありません。数値キーでも同じキーの値を置き換え、利用者が指定しなかったキーは残します。

```php theme={null}
<?php

$defaults = ['channels' => ['mail', 'database']];
$overrides = ['channels' => ['slack']];

$config = array_replace_recursive($defaults, $overrides);

var_export($config['channels']);
```

```text theme={null}
array (
  0 => 'slack',
  1 => 'database',
)
```

利用者が `['slack']` だけを指定しても、`database` が残ります。また、`['channels' => []]` を渡してもデフォルトのリストは空になりません。通知先やミドルウェアなど、リスト全体の指定に意味がある設定では特に注意してください。

このような設定を持つ場合は、リストと部分上書き可能な連想配列を別の最上位キーに分けて浅いマージを使うなど、設定の構造から検討します。すでに公開したパッケージでマージ方式を変更すると、同じ設定ファイルでも挙動が変わるため、単なる実装の置き換えとして扱わないでください。

## 設定キャッシュにはマージ後の値が保存される

両メソッドは、アプリケーションが `CachesConfiguration` を実装し、`configurationIsCached()` が `true` の場合にはマージ処理をスキップします。通常のLaravelアプリケーションでは、設定キャッシュが存在する起動がこれに該当します。

`ConfigCacheCommand` は古い設定キャッシュを削除し、新しいアプリケーションを起動して設定リポジトリ全体を取得します。その起動でプロバイダーの設定がマージされ、結果がキャッシュファイルに保存されます。以降の起動では `LoadConfiguration` がその値を読み込みます。

```mermaid theme={null}
flowchart TD
    A["php artisan config:cache"] --> B["古い設定キャッシュを削除"]
    B --> C["新しいアプリケーションを起動"]
    C --> D["設定ファイルを読み込み<br>プロバイダーでマージ"]
    D --> E["設定リポジトリ全体を保存"]
    E --> F["以降の起動では保存済み設定を使用<br>両マージメソッドはスキップ"]
```

したがって、パッケージを更新してデフォルト値やマージ方式が変わっても、古いキャッシュを使い続けるアプリケーションには反映されません。設定キャッシュを利用するデプロイでは、更新後のコードで再構築します。

```bash theme={null}
php artisan config:cache
```

開発中にファイルから読み直す状態へ戻したい場合は、`php artisan config:clear` を使います。キャッシュの生成場所を独自に決めず、Laravelのコマンドに管理を任せてください。

<Warning>
  設定ファイルにClosureを定義しないでください。`config:cache` で正しくシリアライズできません。コールバックを渡したい場合は、設定にはクラス名などを置き、実際のサービスの登録はプロバイダーで行います。
</Warning>

## 設定変更をリリースする前の確認

パッケージのテストでは、未公開の設定だけでなく、旧バージョンから残っている設定を入力として扱います。

* 設定未公開でも、必要なデフォルト値が取得できる。
* 古い公開済み設定で、利用者の値が優先され、新しい項目が設計どおり補われる。
* ネストした配列、数値キーのリスト、空配列について、上書きの契約が変わらない。
* 利用アプリケーションで `config:cache` が成功し、キャッシュを使う別の起動でも同じ設定になる。

新しいキーのデフォルト値と、必要なキャッシュ再構築をリリースノートに記載します。キーの削除・改名やマージ方式の変更は、利用者の公開済み設定との互換性も含めて判断します。

## 関連ページ

<Columns cols={2}>
  <Card title="パッケージのテスト" icon="flask" href="/jp/advanced/package-testing">
    サービスプロバイダーを登録して、設定やサービスの動作を検証します。
  </Card>

  <Card title="バージョン互換性管理" icon="code-branch" href="/jp/advanced/package-versioning">
    公開APIの変更をリリース方針と継続的なメンテナンスに結び付けます。
  </Card>
</Columns>

## 参照した一次情報

* [Laravel公式ドキュメント: パッケージ設定](https://github.com/laravel/docs/blob/13.x/packages.md#configuration)
* [ServiceProvider: マージと公開の実装](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Support/ServiceProvider.php)
* [ConfigCacheCommand: 設定キャッシュの生成](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Foundation/Console/ConfigCacheCommand.php)
* [LoadConfiguration: 設定の読み込み](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php)
* [ConfigClearCommand: 設定キャッシュの削除](https://github.com/laravel/framework/blob/v13.34.0/src/Illuminate/Foundation/Console/ConfigClearCommand.php)


## Related topics

- [Laravelパッケージ開発](/jp/advanced/package-development.md)
- [応用トピック](/jp/advanced/index.md)
- [キャッシュ](/jp/cache.md)
- [パッケージ自動検出の内部構造](/jp/advanced/package-discovery.md)
- [遅延サービスプロバイダー](/jp/advanced/deferred-provider.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.