エラー

PHPで発生する『Trying to Get Property of Non-Object』エラーの原因と対策について解説

PHP開発中に「php trying to get property of non-object」というエラーが表示される場合、変数がオブジェクトとして認識されていない可能性があります。

この記事では、エラー発生の背景と具体的な対策方法について簡潔に説明します。

エラー発生の背景と原因

PHPにおけるオブジェクトの基本的な扱い

オブジェクトと変数の関係性

PHPでは、オブジェクトはクラスのインスタンスとして生成され、変数に格納されるときは基本的に参照として扱われます。

たとえば、下記のサンプルコードでは、変数$object1$object2は同じインスタンスを指すため、どちらか一方のプロパティの変更がもう一方に反映されることがあります。

<?php
// クラスUserの定義
class User {
    public $name;
}
// Userオブジェクトの生成
$object1 = new User();
$object1->name = "Taro";
// 変数の代入で参照が共有される
$object2 = $object1;
$object2->name = "Jiro";
// 結果: $object1->nameも"Jiro"に変更される
echo $object1->name;
?>
Jiro

このように、オブジェクトは変数の単なるコピーではなく、同じインスタンスを指すため、変数の状態確認が重要になります。

オブジェクト生成のタイミングについて

オブジェクトは主にnewキーワードを使って生成されます。

生成タイミングがずれると、初期化されていない変数に対してプロパティを取得しようとするエラーが発生する可能性があります。

下記の例では、オブジェクト生成前にプロパティにアクセスしようとするため、エラーが発生します。

<?php
// 変数の初期化前にプロパティアクセス
echo $user->name;  // $userはまだオブジェクトではないためエラー
?>

このエラーは、オブジェクト生成のタイミングが原因で起こる典型的な例です。

『Trying to Get Property of Non-Object』エラーが起こるシナリオ

典型的なコード例と状況

「Trying to Get Property of Non-Object」エラーは、オブジェクトとして期待される変数が実際にはnullやその他の非オブジェクト値になっている場合に発生します。

次の例は、データベースから値を取得する際にオブジェクトが正しく返されなかった場合の状況を示しています。

<?php
// fetchData関数は通常、Userオブジェクトを返すが、失敗時はnullを返す
$user = fetchData("SELECT * FROM users WHERE id = 1");
// 取得結果がnullの場合、プロパティへのアクセスでエラーが発生する
echo $user->name;
?>
PHP Notice:  Trying to get property of non-object in <filename> on line <line number>

ここでは、データが取得できず$usernullになっているため、プロパティにアクセスするコードでエラーが発生します。

エラー発生パターンの比較

エラーが発生するパターンとして主に以下のケースが考えられます。

  • 変数の初期化漏れや未定義変数に対してプロパティアクセス
  • 関数やメソッドの戻り値として期待するオブジェクトが返されず、nullや配列が返された場合
  • オブジェクトの生成前にプロパティにアクセスしようとした場合

たとえば、返り値が配列になっていると期待してコードを書いた場合でも、実際にはオブジェクトが返されるべきだった状況など、利用する側と返す側の整合性が取れていないとエラーが発生します。

エラー発生時の検証手法

変数状態の確認とデバッグ方法

var_dump()やprint_r()の利用方法

エラー発生時には、変数の状態を確認することが大切です。

var_dump()print_r()を使用して、変数がどのような値や型を持っているか確認することができます。

以下のサンプルコードは、変数$userの中身を確認する例です。

<?php
// 仮のfetchData関数で、失敗時にnullを返す
$user = fetchData("SELECT * FROM users WHERE id = 1");
// 変数の内容を確認
var_dump($user);
print_r($user);
// その後プロパティにアクセスするときは条件分岐を活用する
if (is_object($user)) {
    echo $user->name;
}
?>
NULL

このように、デバッグツールを使用し、変数が期待される型・値を持っているかをチェックすることがエラーの原因究明に役立ちます。

エラーログの確認ポイント

PHPのエラーログには、エラー発生箇所やその詳細な情報が記録されているため重要な情報源となります。

エラーログを確認するときは、以下の点に注意してください。

  • エラーメッセージの内容と発生箇所
  • 発生前後の処理状況
  • 他のエラーや警告が関連していないかの確認

これにより、どの処理がエラーの原因になっているのかを効率的に特定することができます。

エラーメッセージ解析のテクニック

メッセージに隠れたヒントの抽出法

エラーメッセージには、エラーが発生したファイル名や行番号、場合によっては変数の状態に関するヒントが含まれています。

たとえば、「Trying to get property of non-object」というエラーは、オブジェクトでない変数に対してプロパティアクセスが行われたことを示しています。

これにより、次の点を確認することが重要です。

  • 変数が正しく初期化されているか
  • 関数の戻り値が期待通りの型になっているか
  • コードの実行順序や条件分岐に問題がないか

各エラーメッセージの詳細情報を照らし合わせることで、問題の根本原因を探ることが可能となります。

エラー対策の実践例

基本的な対策の考え方

初期化処理と型チェックの重要性

オブジェクトを使用する前に、変数の初期化や型チェックを行うことで、エラーを事前に回避できます。

たとえば、関数から返された値の型が期待通りか確認し、そうでない場合は適切な初期値を設定するなど、厳密なチェックを実施することが重要です。

<?php
// fetchData関数から返された値がオブジェクトかどうかを確認
$user = fetchData("SELECT * FROM users WHERE id = 1");
if (is_object($user)) {
    echo $user->name;
} else {
    // 万一の場合の初期化やエラー処理
    echo "ユーザ情報が存在しません。";
}
?>
ユーザ情報が存在しません。

この例では、変数が期待した型でない場合の分岐を設けることで、余計なエラーを防ぐ方法を示しています。

修正方法の具体的手法

オブジェクト生成処理の改善策

オブジェクトが適切に生成されるように、生成処理そのものを改善することが求められます。

たとえば、関数内で返す値を厳密にチェックし、必要な場合は例外処理を実装することで、エラーの発生を未然に防ぐことができます。

<?php
// 改善版fetchData関数。エラー時には例外を投げる
function fetchData($query) {
    // 仮の処理として、データ取得に失敗した場合
    if (/* 取得失敗条件 */ false) {
        throw new Exception("データ取得に失敗しました。");
    }
    return new User();  // 正常の場合はUserオブジェクトを返す
}
try {
    $user = fetchData("SELECT * FROM users WHERE id = 1");
    echo $user->name;
} catch (Exception $e) {
    echo $e->getMessage();
}
?>
データ取得に失敗しました。

例外処理を取り入れることで、オブジェクト生成に関する問題を明示的に扱うことができ、後続のエラー発生を防ぎやすくなります。

条件分岐によるエラー回避方法

オブジェクトに対してプロパティアクセスを行う前に、変数がオブジェクトであるかどうかを条件分岐でチェックすることも有効です。

簡単な例として、以下のコードでは変数の型をチェックしてからプロパティにアクセスしています。

<?php
// fetchData関数でオブジェクトが返る前提の処理
$user = fetchData("SELECT * FROM users WHERE id = 1");
// オブジェクトかどうかを確認してからプロパティアクセス
if (is_object($user)) {
    echo $user->name;  // 安全にプロパティへアクセス
} else {
    echo "エラー: オブジェクトが取得できませんでした。";
}
?>
エラー: オブジェクトが取得できませんでした。

この方法は、意図しない値が変数に格納される状況に対して有効な対策となります。

再発防止とテスト戦略

ユニットテストでのエラー再現と防止策

テストケース作成のポイント

ユニットテストを活用することで、オブジェクト生成や返り値の検証を自動化し、エラーの再発を防ぐ効果的な手法が得られます。

テストケース作成の際には、以下のポイントを意識してください。

  • 関数やメソッドの返り値が期待する型であるかをチェックする
  • 異常系と正常系の両方のパターンをカバーする
  • 予期しない結果になった場合のエラーメッセージや例外処理を検証する

たとえば、PHPUnitを利用した簡単なテストケースは以下のように記述できます。

<?php
use PHPUnit\Framework\TestCase;
class FetchDataTest extends TestCase {
    public function testFetchDataReturnsUserObject() {
        $user = fetchData("SELECT * FROM users WHERE id = 1");
        $this->assertIsObject($user);
        $this->assertObjectHasAttribute('name', $user);
    }
    public function testFetchDataHandlesFailure() {
        // fetchData関数の失敗パターンを模擬する
        $this->expectException(Exception::class);
        fetchData("INVALID QUERY");
    }
}
?>
PHPUnit 9.x.x by Sebastian Bergmann and contributors.
....
Time: 00:00.012, Memory: 6.00 MB
OK (2 tests, 3 assertions)

このようなテストを通じ、オブジェクトが期待通りに生成されるかどうか、また、エラー発生時の処理が正しく行われるかを検証できます。

コードレビューと静的解析ツールの活用

ツール導入による改善の実例

コードレビューや静的解析ツールを活用することで、プロジェクト全体のコード品質を向上させ、オブジェクトの取り扱いに関する問題を早期に発見できます。

代表的な静的解析ツールとしては、PHPStanやPsalmがあります。

たとえば、PHPStanを使用してコードを解析した場合、オブジェクトの初期化漏れや型不一致について警告が出されるため、未然にエラー発生を防ぐ助けになります。

# PHPStanを使用して解析を実行する例

vendor/bin/phpstan analyse src

解析結果には、オブジェクトが正しく扱われていない箇所について具体的な指摘が表示されるため、コードレビューの有用な補助情報となります。

これにより、見落としがちなミスを防ぐとともに、チーム全体でのコード品質向上が期待できます。

まとめ

本記事では、PHPにおけるオブジェクトの基本的な扱いから、『Trying to Get Property of Non-Object』エラーの原因、検証手法、対策、そして再発防止策について詳しく解説しました。

全体を通じて、エラー発生時の原因特定と対策実施方法の理解が深まる内容でした。

早速、実践環境で提示した方法を試し、エラー解消とコードの品質向上に取り組んでみてください。

関連記事

Back to top button
目次へ