クラスとオブジェクト——現実世界をコードで表現する
オブジェクト指向とは何か
プログラミングを学び始めると、最初は「手続き型」のコードを書きます。上から順番に処理を書いていくスタイルです。これでも小さなプログラムなら十分ですが、コードが大きくなると管理が難しくなってきます。
オブジェクト指向プログラミング(OOP)は、現実世界の「モノ」をコードに落とし込む考え方です。人、商品、注文——こうした現実のモノをプログラム上の「オブジェクト」として表現し、それぞれが自分のデータと振る舞いを持ちます。
このシリーズでは、OOPの核となる概念をPHP 8.xのコードを使いながら一つずつ丁寧に解説していきます。
クラスとオブジェクトの関係
まず最も大切な概念を押さえましょう。
- クラス = 設計図
- オブジェクト = 設計図から作られた実体(インスタンス)
たとえば「人間」というクラスがあれば、「田中さん」「鈴木さん」はそれぞれ別々のオブジェクトです。同じ設計図(クラス)から作られますが、名前や年齢はそれぞれ異なります。
手続き型との比較
手続き型で「人」を表現しようとするとこうなります。
// NG例:手続き型
$name = '田中太郎';
$age = 30;
function greet(string $name): string {
return "こんにちは、{$name}です。";
}
echo greet($name);
データと処理がバラバラです。人が増えるほど変数も関数も増えていき、どこに何があるかわからなくなります。
PHPでクラスを定義する
オブジェクト指向では、関連するデータと処理をひとまとめにします。
// OK例:クラスを使う
class Person
{
public string $name;
public int $age;
public function greet(): string
{
return "こんにちは、{$this->name}です。";
}
}
$person = new Person();
$person->name = '田中太郎';
$person->age = 30;
echo $person->greet(); // こんにちは、田中太郎です。
class キーワードでクラスを宣言し、new キーワードでオブジェクト(インスタンス)を作ります。$this はそのオブジェクト自身を指します。
コンストラクタ——オブジェクトを初期化する
上の例では、オブジェクトを作った後に $person->name = ... と別々に値をセットしていました。これは少し不便です。コンストラクタを使えば、オブジェクト生成時に初期値をまとめてセットできます。
class Person
{
public string $name;
public int $age;
// コンストラクタ:new Person() のときに自動で呼ばれる
public function __construct(string $name, int $age)
{
$this->name = $name;
$this->age = $age;
}
public function greet(): string
{
return "こんにちは、{$this->name}です。{$this->age}歳です。";
}
}
$person = new Person('田中太郎', 30);
echo $person->greet(); // こんにちは、田中太郎です。30歳です。
__construct という特別なメソッドがコンストラクタです。new Person('田中太郎', 30) と書くと自動的に呼ばれます。
PHP 8.0 のコンストラクタプロモーション
PHP 8.0以降では、コンストラクタの引数宣言とプロパティ定義を一度に書ける「コンストラクタプロモーション」が使えます。コードがスッキリします。
class Person
{
// public をつけるだけでプロパティとして宣言・代入される
public function __construct(
public string $name,
public int $age,
) {}
public function greet(): string
{
return "こんにちは、{$this->name}です。{$this->age}歳です。";
}
}
$person = new Person('田中太郎', 30);
echo $person->greet();
プロパティとメソッド
クラスの構成要素を整理しましょう。
| 用語 | 意味 | 例 |
|---|---|---|
| プロパティ | クラスが持つデータ(変数) | $name, $age |
| メソッド | クラスが持つ処理(関数) | greet() |
| インスタンス | クラスから生成されたオブジェクト | new Person(...) |
メソッドをもう少し充実させてみましょう。
class Person
{
public function __construct(
public string $name,
public int $age,
) {}
public function greet(): string
{
return "こんにちは、{$this->name}です。";
}
public function isAdult(): bool
{
return $this->age >= 18;
}
public function haveBirthday(): void
{
$this->age++;
}
}
$person = new Person('山田花子', 17);
echo $person->isAdult() ? '成人' : '未成年'; // 未成年
$person->haveBirthday();
echo $person->isAdult() ? '成人' : '未成年'; // 成人
isAdult() は「成人かどうか」を返すメソッド、haveBirthday() は誕生日を迎えて年齢を増やすメソッドです。オブジェクトが自分自身のデータを操作しています。
複数のオブジェクトを作る
同じクラスから複数のオブジェクトを作れます。それぞれ独立したデータを持ちます。
$alice = new Person('Alice', 25);
$bob = new Person('Bob', 32);
$alice->haveBirthday();
echo $alice->age; // 26
echo $bob->age; // 32(Aliceの操作は影響しない)
$alice と $bob は別々のオブジェクトなので、一方を変更しても他方には影響しません。
まとめ
この記事では、OOPの基本中の基本を学びました。
- クラスはデータと処理をまとめた設計図
- オブジェクトは
newで作るクラスの実体 - コンストラクタ
__construct()でオブジェクト生成時の初期化ができる - プロパティはオブジェクトのデータ、メソッドはオブジェクトの振る舞い
- PHP 8.0のコンストラクタプロモーションでコードを簡潔にできる
次回はカプセル化——プロパティを外部から直接操作させない仕組みについて学びます。「なぜプロパティを public にしてはいけないのか」という疑問に答えます。