Menu

PHPのクラスとオブジェクト:プロパティ、メソッド、$this

PHPのクラスはclass Name { }で宣言する設計図で、new Name()でそこからオブジェクトを作ります。プロパティ、メソッド、$this、public/private/protected、型付きプロパティとreadonlyプロパティ、__toString、オブジェクトを代入してもコピーされない理由を学びます。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

PHPのクラスはclass Name { ... }で宣言し、プロパティ(変数)とメソッド(関数)を持ちます。new Name()でそこからオブジェクトを作り、->でプロパティを読んだりメソッドを呼んだりします:$user->name、$user->greet()。

クラスは設計図で、オブジェクトはそこから作られた1つの物です。1つのクラスから必要なだけオブジェクトを作れ、それぞれが独自のプロパティの値を持ちます。

プロパティとメソッド

プロパティは、アクセス修飾子、任意の型、任意のデフォルト値で宣言します。メソッドはクラスの中の関数です。メソッドの中では、$thisはそのメソッドが呼ばれたオブジェクトなので、$this->balanceはそのオブジェクトの残高を読みます。

各オブジェクトは自分の$balanceを持つので、$aに入金しても$bには影響しません。newのあとでプロパティを1つずつ設定するのは面倒なので、コンストラクタで初期値を引数として受け取ります。

public、private、protected

アクセス修飾子は、誰がプロパティに触れたりメソッドを呼んだりできるかを決めます。

キーワードアクセスできる場所
publicどこからでも
protectedクラス自身とそれを継承したクラス
private宣言したクラスだけ

プロパティをprivateにしてメソッドを公開するのが、クラスが自分のルールを守る方法です。ここでは残高は、不正な金額を拒否するdeposit()とwithdraw()を通してしか変わりません。

privateなプロパティをクラスの外から読むのは、警告ではなくErrorです。

型付きプロパティと未初期化の値

デフォルト値のない型付きプロパティは、最初は未初期化の状態で、これはnullとは違います。何かを代入する前に読むとErrorが投げられます。デフォルト値を与えるか、コンストラクタで代入するか、?Typeと= nullでnull許容にします。

型は代入のときに強制されます。デフォルト(strictでない)モードでは、$p->stock = '7'は数値文字列を7に変換し、$p->stock = 'many'はTypeErrorを投げます。

readonlyプロパティ

readonlyプロパティ(PHP 8.1)は、クラスの中から1回だけ書き込め、そのあとは二度と書き込めません。金額やIDのような値オブジェクトを作るときの定番の方法です。PHP 8.2では、すべてのプロパティをreadonlyにするreadonly classが追加されました。

readonlyプロパティには型が必要で、デフォルト値は持てません。変更したコピーが必要なら、古いものを編集する代わりに新しいオブジェクトを作ります(new Order('B-2002'))。

__toStringでオブジェクトを出力する

echo $objectは、クラスが__toString()を定義しているときだけ動きます。このメソッドは、echo、文字列の連結、"{$object}"など、オブジェクトがテキストとして扱われるときにPHPが使う文字列を返します。

__toStringがないと、echo $objectはError(「Object of class Money could not be converted to string」)を投げます。デバッグには、どんなオブジェクトにも使え、privateなプロパティも表示するprint_r()とvar_dump()が使えます。var_dumpとprint_rを参照してください。

オブジェクトを代入してもコピーされない

配列に慣れた人がいちばんつまずくミスです。配列を代入するとコピーされますが、オブジェクトを代入するとハンドルだけがコピーされ、両方の変数が同じオブジェクトを指します。

cloneは浅いコピーを作ります。プロパティが別のオブジェクトを持っていれば、両方のコピーがその内側のオブジェクトを共有したままです。===は同じオブジェクトのときだけtrueで、==は同じクラスの2つのオブジェクトのプロパティの値を比べます。オブジェクトを関数に渡すのも代入と同じ動きなので、関数は受け取ったオブジェクトを変更できます。

よくある質問

PHPでクラスからオブジェクトを作るには?

クラス名と一緒にnewを使います:$user = new User();。クラスにコンストラクタがあれば、new User('Ada')のように括弧の中に引数を渡します。そのあと、アロー演算子でメソッドを呼んだりプロパティを読んだりします:$user->name、$user->greet()。

PHPの$thisは何を意味しますか?

$thisは、今のメソッドが呼ばれたオブジェクトです。$ada->greet()の中では$thisは$adaなので、$this->nameはAdaの名前を読みます。staticでないメソッドの中にしか存在しません。

PHPのpublic、private、protectedの違いは何ですか?

publicのメンバーはどこからでも使え、privateのメンバーは宣言したクラスの中からだけ、protectedのメンバーはそのクラスと子クラスから使えます。privateなプロパティを外から読むとErrorが投げられます:Cannot access private property。

PHPのオブジェクトは参照渡しですか?

変数が持っているのはオブジェクトそのものではなく、オブジェクトへのハンドルです。$b = $a;はハンドルをコピーするので、両方の変数が同じオブジェクトを指し、$bを通した変更は$aにも表れます。独立したコピーを得るには$b = clone $a;を使います。

PHPのreadonlyプロパティとは何ですか?

public readonly string $id;と宣言したプロパティ(PHP 8.1以降)は、クラスの中から1回だけ設定でき、そのあとは決して変更できません。2回目に書き込むとErrorが投げられます:Cannot modify readonly property。

Coddyのプログラミング言語のイラスト

Coddyでコードを学ぼう

始める