【PHP】stdClassについてLaravelとテストコードから学ぶ!

PHP
Eslo
Eslo

PHPには「stdClass」という標準クラスがありますが、勉強しているときにでてきたけどこれが一体何なのか、どういう時に使えば良いのか迷う方も多いのではないでしょうか。本記事では、stdClassの基本的な説明から、メリット、デメリット、そして具体的な活用シーンについて解説します。

stdClassとは?

stdClass(Standard Class)は、PHPに標準で用意されている動的なプロパティをもつ軽量なクラスです。

PHP: stdClass - Manual
PHP is a popular general-purpose scripting language that powers everything from your blog to the most popular websites i...

普通であればカスタムクラスを作成し、プロパティを定義します。

class CustomClass
{
    public string $name;
    public int $age;
}

$obj = new CustomClass();

$obj->name = 'Eslo';
$obj->age = 20;

var_dump($obj);

// 出力結果
// object(CustomClass)#1 (2) { ["name"]=> string(4) "Eslo" ["age"]=> int(20) }

stdClassにはメソッドやデフォルトのプロパティはない完全に空のクラスですが、動的にプロパティを追加することができるため以下のようなことができます。

$obj = new stdClass();

// 動的にプロパティを追加
$obj->name = "Eslo";
$obj->age = 20;

var_dump($obj);
// 出力結果
// object(stdClass)#1 (2) { ["name"]=> string(4) "Eslo" ["age"]=> int(20) }

stdClassのメリット

結論から申し上げますと、実務においてstdClassを使用するメリットはほぼないです。

メリットはいくつかあるのですが、具体的な活用シーンで説明します。

stdClassのデメリット

便利そうなのでデメリットないのでは?と思う方もいるかもしれません。そんな方へデメリットをお伝えします。

1. 型の安全性がない

以下のコードが書かれてたとしましょう。

$obj = new stdClass();
$obj->name = "Eslo";    // 文字列
$obj->name = 123;       // 突然整数に変えてもエラーにはならない

実務は1人がコードを触ることのほうが少ないです。自分はnameプロパティをstringで使ってほしいが、他の人が勝手にintに変えてしまった、という可能性があり得ます。

stdClassは動的にプロパティを使用できる分、型の安全性がないのです。

2.意図しないプロパティの追加

ここまで読んできたのであれば以下のコードも理解することができます。

// SNSで自分がフォローしている人の情報を返すAPI
$obj = new stdClass();
$obj->nickname = "Eslo";

// 個人情報も追加しておくか・・・と勝手に個人情報を足した
$obj->email = "eslo@eslo.jp";

例えば上記のオブジェクトがAPIのレスポンスで返されていた場合、自分がフォローしている人のメールアドレスを閲覧できてしまいます。

本来の意図と異なるデータが混ざってしまう可能性もあるということです。

厄介なのは動的にプロパティを定義できるため、本来の意図とは異なるデータが混ざる可能性があること、それが簡単にできてしまうことです。

3.拡張性も保守性も低い

例えば以下のオブジェクトを他ファイルでも頻繁に使用する場合、同じコードが重複してしまいます。

// $objを他ファイルでも使う場合、同じコードを書くことになる
$obj = new stdClass();

$obj->name = 'Eslo';
$obj->age = 20;

それであれば最初からカスタムクラスを作成したほうがクラスの利用目的も明確ですし、クラスにプロパティを追加した場合でもカスタムクラスが使われているところを追えば修正が楽ですよね。

stdClassを使いまくっているプロジェクトは見たことないですが、「stdClass」でgrepしてたくさんでてきたら発狂する自信があります(笑)

具体的な活用シーン

1.json_decodeでの活用

Laravelを利用している人は外部APIを呼び出した後、json_decodeをするのではないのでしょうか。

json_decodeを使用するとstdClassが活用されています。

外部APIのレスポンスなどをいちいち専用クラスを用意して、プロパティを定義してなどしなくていいのは便利ですね。

実はこんなところでstdClassの恩恵を受けている場合もあります。

$json = '{"name": "鈴木次郎", "age": 40}';

// stdClass形式でデコード(第二引数をtrueにすると連想配列になる)
$obj = json_decode($json); // $objは stdClass オブジェクト

// プロパティにアクセス
echo $obj->name; // 出力: 鈴木次郎
echo $obj->age;  // 出力: 40

2.Laravel内部での活用

以下のコードを見てみましょう。

// vendor/laravel/framework/illuminate/Collections/Collection.php

    public function firstOrFail($key = null, $operator = null, $value = null)
    {
        $filter = func_num_args() > 1
            ? $this->operatorForWhere(...func_get_args())
            : $key;

        $placeholder = new stdClass();

        $item = $this->first($filter, $placeholder);

        if ($item === $placeholder) {
            throw new ItemNotFoundException;
        }

        return $item;
    }

このコードは、コレクション内で条件に一致する最初の要素を取得するメソッド firstOrFail の実装であり、検索結果が存在しない場合に例外をスローする仕組みを提供しています。

stdClassを活用する理由は以下の通りです。

一意性の確保

$placeholder には新しい stdClass のインスタンスが設定されます。このインスタンスは常に一意であり、通常のコレクション内の要素と一致する可能性がありません。そのため、$item === $placeholder という判定が正確に「検索結果が存在しない」ことを示します。

軽量なオブジェクト

stdClass は PHP の組み込みクラスで、不要なプロパティやメソッドを持たないため、専用のプレースホルダー用クラスを作成するよりも軽量です。

逆にシンプルという点

プレースホルダー用の専用クラスを定義することなく、すぐに利用可能な stdClass を活用することで、コードベースをシンプルに保てます。

3.テストコードでの活用

テストコードを書くときにも役に立ちます。例えば以下のようなコードです。

// テスト用のモックオブジェクトを作成
$mockUser = new stdClass();
$mockUser->name = "テストユーザー";
$mockUser->email = "test@example.com";

// テスト関数に渡す
$result = someFunction($mockUser);

まとめ

stdClassは、PHPに標準で用意された軽量なクラスで、空のオブジェクトや動的なデータ操作に役立ちます。しかし、その柔軟性ゆえに型安全性や可読性が低下するデメリットがあるため、実務では動的プロパティを乱用しないことが重要です。

一方で、JSONデコード結果やプレースホルダー、一時的なデータ保持、テスト用のモックデータなど、特定の用途では非常に便利に活用できます。stdClassの特徴を理解し、適切な場面で活用することで、効率的なコードを書くことが可能になります。

stdClassを「何でもできる便利ツール」として使うのではなく、用途に合わせた明確な役割を持たせることが重要です。そのためにこのような記事を書きました。