PHP - use 文によるインポート

名前空間を使うと、クラスの完全修飾名は App\Http\Controllers\UserController のように長くなる。毎回この名前をフルで書くのは現実的ではない。use 文を使えば、クラスや関数、定数をインポートして短い名前で参照できるようになる。

use 文の基本

use 文はファイルの先頭、namespace 宣言の直後に記述する。インポートしたクラスは、以降そのクラス名だけで使えるようになる。

<?php

namespace App\Services;

use App\Models\User;
use App\Repositories\UserRepository;

class UserService
{
    private UserRepository $repository;

    public function find(int $id): User
    {
        return $this->repository->findById($id);
    }
}

use App\Models\User と宣言することで、\App\Models\User と書く代わりに単に User と書けるようになった。コードの可読性が大きく向上する。

use 文がない場合との比較

use 文を使う場合と使わない場合で、同じ処理がどれほど違って見えるか確認してみよう。

use 文なし

毎回 \App\Models\User\App\Repositories\UserRepository のようにフルパスを書く必要があり、コードが冗長になる

use 文あり

ファイル冒頭で一度インポートすれば、以降は UserUserRepository だけで済み、コードが簡潔になる

ただし use 文は「名前の短縮」であって、クラスを自動的に読み込む機能ではない。ファイルの読み込み自体はオートローダー(PSR-4)が担当しており、use 文はあくまで名前解決の仕組みだという点に注意が必要だ。

エイリアス(as)

同じクラス名が異なる名前空間に存在する場合、そのままインポートすると名前が衝突する。as キーワードでエイリアス(別名)を付ければ、この問題を回避できる。

<?php

namespace App\Services;

use App\Models\User as AppUser;
use External\Auth\User as AuthUser;

class MigrationService
{
    public function migrate(AuthUser $source): AppUser
    {
        return new AppUser($source->getName());
    }
}

App\Models\UserExternal\Auth\User はどちらもクラス名が User だが、asAppUserAuthUser に分けることで共存させている。

エイリアスを使う典型的な場面をまとめておこう。

同名クラスの衝突回避

上の例のように、異なるパッケージに同名のクラスがある場合。Laravel では Illuminate\Support\Facades\RequestIlluminate\Http\Request の使い分けでよく見かける。

長い名前の短縮

VeryLong\Namespace\Path\SomeClassName のような深い階層のクラスを SomeName のように縮めたい場合にも有効だ。

関数・定数のインポート

use 文はクラスだけでなく、関数や定数もインポートできる。それぞれ use functionuse const を使う。

<?php

namespace App\Utils;

use function App\Helpers\formatDate;
use function App\Helpers\formatCurrency;
use const App\Config\DEFAULT_LOCALE;

class Formatter
{
    public function format(int $timestamp): string
    {
        return formatDate($timestamp, DEFAULT_LOCALE);
    }
}

クラスの use とは異なり、use functionuse const は実務ではそこまで頻繁に使われない。ほとんどのプロジェクトではクラスベースの設計が主流であり、名前空間付きの関数や定数を定義する機会自体が少ないためだ。

グループ use 宣言

PHP 7.0 以降、同じ名前空間から複数のクラスをインポートする場合、波括弧でグループ化できるようになった。

<?php

namespace App\Services;

use App\Models\{User, Post, Comment};
use App\Repositories\{UserRepository, PostRepository};

class ContentService
{
    // User, Post, Comment, UserRepository, PostRepository が使える
}

グループ use を使うと、共通部分の繰り返しがなくなりインポート部分がすっきりする。

個別 use

use App\Models\User; use App\Models\Post; use App\Models\Comment; と 3 行必要

グループ use

use App\Models\{User, Post, Comment}; の 1 行で完結する

ただしグループ内に多くのクラスを詰め込みすぎると、かえって読みにくくなる。1 グループあたり 3〜5 クラス程度に留めるのが実用的だろう。

use 文の配置ルールとスコープ

use 文を書く位置には明確な決まりがある。

namespace 宣言

use 文(インポート)

クラス定義や関数定義

この順序は PSR-12 コーディング規約でも定められている。use 文をクラス定義の途中やメソッド内に書くことはできず、必ずファイルの冒頭部分にまとめなければならない。

<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\User;
use App\Services\UserService;
use Illuminate\Http\JsonResponse;

class UserController
{
    public function __construct(
        private UserService $service
    ) {}

    public function show(int $id): JsonResponse
    {
        $user = $this->service->find($id);
        return new JsonResponse($user);
    }
}

declarenamespaceuse → クラス定義という流れが、PHP ファイルの標準的な構造だ。多くの IDE やコードフォーマッターもこの順序を前提としており、守っておけば自動整形との相性も良い。

もう一つ押さえておくべきなのは、use 文の効果はそのファイルの中だけに限定されるという点だ。あるファイルで use App\Models\User と書いても、別のファイルには一切影響しない。Python の import や Java の import と同様に、使うファイルごとに毎回 use 文を書く必要がある。「一度書けばプロジェクト全体に反映される」という誤解は初学者に多いが、use はあくまでファイルローカルな名前解決だ。

trait の use との違い

PHP にはもう一つ別の use がある。クラスの内部で trait を取り込むときに使う use だ。

<?php

namespace App\Models;

use App\Traits\HasTimestamps;  // 名前空間の use(名前解決)

class Post
{
    use HasTimestamps;  // trait の use(コード合成)
}

同じ use キーワードだが、役割はまったく異なる。ファイル冒頭の use は完全修飾名を短くするための名前解決であり、クラス内部の use は trait のメソッドやプロパティをそのクラスに合成する仕組みだ。書く場所が違うので文法上は曖昧さがないものの、初めて見ると混乱しやすいポイントなので意識しておきたい。

未使用の use 文

インポートしたが実際に使っていない use 文は、コードに悪影響を与えないが、放置すると可読性が下がる。PHP 自体は未使用の use 文に対して警告を出さないため、静的解析ツールや IDE の機能で検出・自動削除するのが一般的だ。PHPStan や PHP-CS-Fixer を導入していれば、未使用のインポートを自動的にクリーンアップしてくれる。

use 文を正しく使いこなせば、名前空間の恩恵を受けながらも簡潔で読みやすいコードが書ける。次はオートローディングとの連携を理解することで、ファイルの読み込みまで含めた全体像が見えてくるはずだ。