この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:2
ページ更新者:T
更新日時:2026-06-11 07:07:02

タイトル: Cannot access protected property Illuminate\Http\Request::$...
SEOタイトル: Laravel「Cannot access protected property

この記事の要点
  • Laravel の Request オブジェクトの内部 protected プロパティに直接アクセスしようとして発生
  • $request->session のような名前を使うと、リクエストパラメータではなく内部プロパティへのアクセスとして解釈される
  • 正しくは $request->input('session') / $request->get('session') でパラメータを取得
  • Request の __get マジックメソッドはパラメータを返すが、protected と名前衝突する場合は protected が優先される
  • 安全策: Form Request クラスまたは $request->input() を統一して使う

エラーの全文と発生条件

ErrorException
Cannot access protected property Illuminate\Http\Request::$session

at /var/www/myapp/app/Http/Controllers/UserController.php:25
    23| public function store(Request $request) {
    24|     $name = $request->name;
>>> 25|     $session = $request->session;   // ← ここでエラー
    26|     // ...
    27| }

このエラーは $request オブジェクトの protected プロパティ名と同じ名前のリクエストパラメータにアクセスしようとした際に発生します。Illuminate\Http\Request およびその親クラス Symfony\Component\HttpFoundation\Request には次のような protected プロパティが定義されています:

protected プロパティ用途
$sessionセッションストアインスタンス
$attributesカスタム属性 (ParameterBag)
$requestPOST ボディ (ParameterBag)
$queryクエリ文字列 (ParameterBag)
$server$_SERVER 相当 (ServerBag)
$files$_FILES 相当 (FileBag)
$cookies$_COOKIE 相当 (ParameterBag)
$headersHTTP ヘッダ (HeaderBag)
$contentリクエストボディ raw
$languages / $charsets / $localeロケール関連
$jsonJSON ボディ
$convertedFilesUploadedFile 配列

フォームに 等を作り、$request->session で取得しようとすると、protected プロパティアクセスとして解釈されて上記エラーになります。

解決策: input() / get() を使う

public function store(Request $request) {
    // ❌ NG(protected と名前衝突する場合に死ぬ)
    $session = $request->session;
    $attrs   = $request->attributes;
    $query   = $request->query;

    // ✅ OK(推奨パターン)
    $session = $request->input('session');
    $attrs   = $request->input('attributes');
    $query   = $request->input('query');

    // ✅ OK(同等)
    $session = $request->get('session');

    // ✅ OK(全部一度に)
    $data = $request->all();
    $session = $data['session'] ?? null;

    // ✅ OK(必要分のみ)
    $data = $request->only(['session', 'name', 'email']);

    // ✅ OK(型キャスト系)
    $age = $request->integer('age');
    $isAdmin = $request->boolean('is_admin');
    $tags = $request->array('tags');
}

Request の __get の挙動

Laravel の Request には __get() マジックメソッドが定義されていて、$request->name のように書くと自動的にリクエストパラメータ → ルートパラメータの順で探します:

// Illuminate\Http\Concerns\InteractsWithInput
public function __get($key) {
    return Arr::get($this->all() + $this->route()->parameters(), $key);
}

しかし PHP は プロパティアクセス時に「実在するプロパティ」を優先し、それが protected / private ならエラーになります。__get はそもそも呼ばれません:

class Foo {
    protected $bar = 'protected value';
    public function __get($k) { return 'magic'; }
}
$f = new Foo();
echo $f->baz;   // 'magic' (__get 呼ばれる)
echo $f->bar;   // Cannot access protected property Foo::$bar  ← __get 呼ばれない

典型的なバグパターン

// ❌ よくあるバグ 1: フォーム名がたまたま session

// Controller
$value = $request->session;   // Cannot access protected property

// ❌ よくあるバグ 2: API パラメータ名と衝突
// POST /api/audit { "request": "..." }
$value = $request->request;   // Cannot access protected property

// ❌ よくあるバグ 3: model 配列のキー
{!! Form::open(['name' => 'cookies']) !!}
$value = $request->cookies;   // Cannot access protected property

// ✅ 解決策: 全部 input() に統一
$session = $request->input('session');
$payload = $request->input('request');
$cookies = $request->input('cookies');

解決策2: Form Request クラスで吸収

パラメータが多い・型が複雑な場合は Form Request クラスを使うと、プロパティ名と衝突しない取り出し方ができます:

php artisan make:request StoreUserRequest
// app/Http/Requests/StoreUserRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest {
    public function authorize(): bool { return true; }

    public function rules(): array {
        return [
            'session'    => 'nullable|string|max:255',
            'attributes' => 'nullable|array',
            'name'       => 'required|string|max:100',
        ];
    }

    public function validated($key = null, $default = null) {
        $data = parent::validated();
        // session 等の特殊キーも安全に取り出せる
        return is_null($key) ? $data : ($data[$key] ?? $default);
    }
}

// Controller
public function store(StoreUserRequest $request) {
    $session = $request->validated('session');   // ← protected 衝突なし
    $attrs   = $request->validated('attributes');
}

そもそも衝突を避けるための命名規則

  • フォームの name= 属性に session / attributes / request / query / server / files / cookies / headers / content / json / locale 等は使わない
  • 使うなら user_session / form_attrs / payload 等にリネーム
  • API では { "data": {...} } でラップする慣習に従う

$request の値取得 API まとめ

メソッド用途
input($k, $default)GET/POST 統合$request->input('name')
get($k, $default)input のエイリアス
query($k, $default)クエリ文字列のみ$request->query('page')
post($k, $default)POST ボディのみ
all()全パラメータ配列$request->all()
only([...])指定キーのみ$request->only(['name','email'])
except([...])指定キー以外$request->except(['_token'])
has($k)存在チェック$request->has('name')
filled($k)存在 + 空でない$request->filled('name')
integer($k) / boolean($k) / array($k)型キャスト取得(Laravel 9+)

FAQ

Q: $request->name という書き方は使ってはいけないのか
A: 動作はします(__get 経由)が、protected プロパティと名前が被ると死ぬ脆さがあるため、チームでは input() に統一するのが安全です。

Q: なぜ Laravel はこの設計にしたのか
A: Symfony Request クラスを継承しているためです。Symfony は元から protected プロパティで内部状態を持つ設計で、Laravel はそれに __get を被せた形になっています。

Q: 自前で Request を拡張すれば直せるか
A: 可能ですが副作用が大きい(フレームワーク内部の挙動が変わる)ので非推奨。アプリ側でフォーム名を変える方が早いです。