メインコンテンツまでスキップ

PHPのクラス基本文法

第1章では、Orderクラスの中身を細かく説明せずに読み進めました。 この章では、privatepublic functionのようなクラスの文法を1つずつ理解していきます。

クラスとプロパティ

クラスはclassキーワードで定義します。 クラスの中に書く変数を、プロパティと呼びます。

class Order
{
private array $items = [];
private string $customerEmail;
}

private array $items = [];は、$itemsという名前のプロパティを宣言しています。 arrayは型宣言で、このプロパティに配列以外の値を代入しようとするとエラーになります。 privateは可視性修飾子で、意味は後述します。

メソッド

クラスの中に定義された関数を、メソッドと呼びます。 メソッドの中では、$thisという特殊な変数を使って、自分自身のプロパティやメソッドにアクセスできます。

class Order
{
private array $items = [];

public function addItem(string $name, int $price): void
{
$this->items[] = ['name' => $name, 'price' => $price];
}
}

$this->itemsは、このオブジェクト自身が持つ$itemsプロパティを指します。

可視性修飾子: public・protected・private

プロパティやメソッドには、クラスの外からどこまでアクセスできるかを決める可視性修飾子を付けます。

  • public: どこからでもアクセスできる
  • protected: 自分自身のクラスと、それを継承したクラスからアクセスできる(継承は第5章で扱います)
  • private: 自分自身のクラスの中からしかアクセスできない
class Order
{
private array $items = [];

public function getItemCount(): int
{
return count($this->items);
}
}

$order = new Order();
$order->getItemCount(); // OK: publicメソッドなので呼び出せる
$order->items; // エラー: privateプロパティなのでクラスの外からアクセスできない

$itemsをprivateにすることで、クラスの外から直接書き換えられることを防いでいます。 この考え方は、第3章「カプセル化と情報隠蔽」で詳しく扱います。

コンストラクタ

オブジェクトを作成するとき(newするとき)に自動的に呼ばれるメソッドを、コンストラクタと呼びます。 PHPでは__constructという名前で定義します。

class Order
{
private string $customerEmail;

public function __construct(string $customerEmail)
{
$this->customerEmail = $customerEmail;
}
}

$order = new Order('taro@example.com');

new Order('taro@example.com')とすると、コンストラクタが呼ばれ、引数$customerEmail$this->customerEmailに代入されます。

コンストラクタプロモーション

コンストラクタでよく書くのが、引数を受け取って同じ名前のプロパティにそのまま代入する、というパターンです。 上のOrderクラスのコンストラクタも、この形をしています。

PHP 8.0では、この定型的な書き方を省略できるコンストラクタプロモーションが導入されました1

❌ Before: プロパティ宣言と代入を別々に書く
class Order
{
private string $customerEmail;

public function __construct(string $customerEmail)
{
$this->customerEmail = $customerEmail;
}
}
✅ After: コンストラクタプロモーション
class Order
{
public function __construct(
private string $customerEmail,
) {
}
}

コンストラクタの引数にprivateのような可視性修飾子を付けると、PHPが自動的に同名のプロパティを宣言し、代入まで行います。 プロパティ宣言と代入の2箇所に分かれていた記述が、1箇所にまとまります。

readonlyプロパティ

PHP 8.1では、初期化した後は値を変更できないreadonlyプロパティが導入されました2

class Order
{
public function __construct(
public readonly string $customerEmail,
) {
}
}

$order = new Order('taro@example.com');
$order->customerEmail = 'jiro@example.com'; // エラー: readonlyプロパティは再代入できない

顧客のメールアドレスのように、一度作成したら変わらないはずの値にreadonlyを付けておくと、意図しない書き換えをPHPの言語機能として防げます。

enum

決まった選択肢の中からしか値を取らないデータを表すために、PHP 8.1ではenum(列挙型)が導入されました3

enum OrderStatus
{
case Pending;
case Shipped;
case Delivered;
}

$status = OrderStatus::Pending;

文字列や整数のような値と組にしたいときは、backed enumを使います。

enum OrderStatus: string
{
case Pending = 'pending';
case Shipped = 'shipped';
case Delivered = 'delivered';
}

echo OrderStatus::Pending->value; // 'pending'

OrderStatus::Pendingという値は、'pending'という文字列や1という数値よりも、意図を明確に表せます。 文字列のtypoによるバグも、PHPの型システムが検出します。

まとめ

  • クラスの中の変数をプロパティ、関数をメソッドと呼ぶ
  • 可視性修飾子(public・protected・private)で、クラスの外からのアクセス範囲を制御する
  • コンストラクタ(__construct)は、オブジェクト生成時に呼ばれる
  • コンストラクタプロモーション(PHP 8.0)は、プロパティ宣言と代入を1箇所にまとめる短縮記法
  • readonlyプロパティ(PHP 8.1)は、初期化後の再代入を防ぐ
  • enum(PHP 8.1)は、決まった選択肢しか取らない値を型として表現する

次に読む

次章では、カプセル化と情報隠蔽を扱います。 public propertyの危険性や、ゲッター・セッターの要否をどう判断するかを見ていきます。

練習問題

次のクラスをコンストラクタプロモーションとreadonlyプロパティを使って書き直してください
class Product
{
private string $name;
private int $price;

public function __construct(string $name, int $price)
{
$this->name = $name;
$this->price = $price;
}

public function getName(): string
{
return $this->name;
}

public function getPrice(): int
{
return $this->price;
}
}

解答例

class Product
{
public function __construct(
private readonly string $name,
private readonly int $price,
) {
}

public function getName(): string
{
return $this->name;
}

public function getPrice(): int
{
return $this->price;
}
}

コンストラクタプロモーションでプロパティ宣言と代入をまとめ、readonlyを付けることで、$name$priceが生成後に変更されないことを保証しています。


Footnotes

  1. 出典: Constructor Promotion(PHP公式マニュアル)。PHP 8.0.0で導入されました。

  2. 出典: Readonly properties(PHP公式マニュアル)。PHP 8.1で導入されました。

  3. 出典: Enumerations(PHP公式マニュアル)。PHP 8.1で導入されました。