オブジェクト指向プログラミング(情報と処理をひとまとめ)
ここまでで、
順番・条件分岐・繰り返し・変数・配列・関数・モジュール化・ディレクトリ構成
といった、プログラミングの「土台」を一通り見てきました。
ここからは、ガチで開発していきたいならほぼ必須なレベルのオブジェクト指向プログラミングの基礎を勉強していきます。
オブジェクト指向プログラミングは、これまで学んできた「変数・関数・配列・モジュール化」を、もう一段きれいにまとめた考え方です。
オブジェクト指向プログラミングでは
- データ(情報)
- それを使う処理(関数)
をひとまとめにして扱うようになります。
これにより、コードが読みやすくなり、大きなアプリでも管理しやすくなります。
クラス(設計図)
クラスとは、「こういう情報と、こういう動きを持ったものを作りますよ」という 設計図 のことです。
たとえば、大体のアプリには「ユーザー」の情報を見られる機能がありますよね。
- ユーザー名がある
- メールアドレスがある
- 年齢がある
- 「プロフィールを表示する」という動きがある
この
- どんな情報を持つか
- どんな動きをするか
を まとめて書いたもの がクラスです。
このクラス自体は、まだユーザーそのものではありません。
- クラス → 設計図
- 実際のユーザー → これから作るもの
という関係になります。
なので、クラスを書いただけでは、まだ何も起こりません。
クラスの書き方はこちら。
<?php
// ユーザーの設計図(クラス)
// class クラス名 { } がクラスの基本の書き方
class User {
// public は、このクラスの外からも使ってOKな情報を設定する、という意味
public $name; // ユーザー名
public $email; // メールアドレス
public $age; // 年齢
// User クラス専用の関数(これをメソッドと呼びます)
public function showProfile() {
// $this は「このユーザー自身」を指す
// -> は「〜の」という意味
echo $this->name . "(" . $this->age . "歳)\n";
// ユーザーの名前(年齢)を表示する
echo "メール:" . $this->email . "\n";
// ユーザーのメールアドレスを表示する
}
}
?>このコードでは、
$name、$email、$age
→ このユーザーが持つ情報showProfile()
→ このユーザーができる動き
を、ひとまとめ にしています。
これが クラス です。
同じ設計図から何人分でもユーザーを作れるため、大量のデータを安全に・整理して扱えるようになります。
次の章で、この 設計図から実際にユーザーを作る= オブジェクト を見ていきます。
オブジェクト(設計図から実体を作る)
大体のアプリのユーザー情報を見ると、ユーザー名には自分の名前などが入っていますよね。
先ほどのコードでいうと、クラス(設計図)の段階では、「名前」や「年齢」といった項目だけが決まっていて、実際の値はまだ入っていない状態でした。
そこに実際の名前や年齢といった中身が入って、実体として作られたものをオブジェクトと呼びます。
オブジェクトを作る書き方はこちら。
クラスからオブジェクトを作るときは new を使います。
<?php
// ユーザーの設計図(クラス)
class User {
public $name;
public $email;
public $age;
public function showProfile() {
echo $this->name . "(" . $this->age . "歳)\n";
echo "メール:" . $this->email . "\n";
}
}
// ↓ ここからがオブジェクト
$user1 = new User(); // Userクラスから「ユーザー1人分」を作る
$user2 = new User(); // もう1人、別のユーザーを作る
?>この時点で、
$user1$user2
は 別々のユーザー です。
今の時点ではオブジェクトである$user1も$user2も中身は空っぽなので、情報を入れていきましょう。
<?php
$user1->name = "田中";
$user1->email = "tanaka@example.com";
$user1->age = 25;
$user2->name = "佐藤";
$user2->email = "sato@example.com";
$user2->age = 32;
?>先ほども少し出てきましたが、ここで出てきた -> は、
「このオブジェクトの中の〜」
という意味です。
$user1->name
→ 「user1 の name」$user2->age
→ 「user2 の age」
と思えばOKです。
クラスでshowProfile()という、名前と年齢、メールアドレスを表示するメソッド(クラス専用の関数を)を作成していましたね。
今この時点で中身が入った$user1と$user2のそれぞれのshowProfile()がちゃんと動くようになっているので、実行してみましょう。
<?php
$user1->showProfile();
$user2->showProfile();
?>
田中(25歳)
メール:tanaka@example.com
佐藤(32歳)
メール:sato@example.com
今の状態を表にするとこうなります。
| 種類 | 名前 | name | age | |
|---|---|---|---|---|
| クラス | User | 箱だけ | 箱だけ | 箱だけ |
| オブジェクト | user1 | 田中 | tanaka@example.com | 25 |
| オブジェクト | user2 | 佐藤 | sato@example.com | 32 |
このように、オブジェクトは クラスから作られた実体で、同じクラスから、何個でも別のオブジェクトを作ることができます。
継承(共通点を引き継ぐ)
継承とは何かというと――
すでに作ったクラスの「共通部分」を、そのまま引き継いで使う仕組み
です。
たとえば、先ほどユーザー情報を表示するクラスを作りましたが、こんな感じで特別なユーザーだけ表示をちょっと変えたい場合…
- VIPユーザー:名前の横に「VIP★」を付けたい
- BANユーザー:名前の横に「(利用停止)」を付けたい
extendsという命令を使って、こんなふうに継承することができます。
<?php
// ================================
// 親クラス:一般ユーザーの基本設計図
// 「ユーザーとして共通の情報」と「基本の表示」をまとめる
// ================================
class User {
public $name;
public $email;
// プロフィール表示(基本形)
public function showProfile() {
echo $this->name . " / " . $this->email . "\n";
}
}
// ================================
// 子クラス1:VIPユーザー
// extends User = 「Userの中身(プロパティやメソッド)を引き継ぐ」
// その上で、VIPだけ表示を変えたいので showProfile() を上書きする
// ================================
class VipUser extends User {
// 親のshowProfile()を「VIPっぽく」差し替える(上書き)
public function showProfile() {
echo "VIP★ . $this->name . " / " . $this->email . "\n";
}
}
// ================================
// 子クラス2:BANユーザー(利用停止)
// 同じくUserを引き継ぎつつ、表示だけ変える
// ================================
class BannedUser extends User {
// 親のshowProfile()を「利用停止」として表示する(上書き)
public function showProfile() {
echo $this->name . "(利用停止) / " . $this->email . "\n";
}
}
// ==================================
// ここから実体(オブジェクト)を作って比較
// ==================================
// 一般ユーザー
$user = new User();
$user->name = "田中";
$user->email = "tanaka@example.com";
// VIPユーザー
$vip = new VipUser();
$vip->name = "佐藤";
$vip->email = "sato@example.com";
// BANユーザー
$banned = new BannedUser();
$banned->name = "鈴木";
$banned->email = "suzuki@example.com";
// 表示
$user->showProfile();
$vip->showProfile();
$banned->showProfile();
?>
田中 / tanaka@example.com
VIP★ 佐藤 / sato@example.com
鈴木(利用停止) / suzuki@example.com
このように「共通している部分」を毎回コピペして書くのではなく、
まとめて1か所に置いて、必要なところだけ引き継ぐ
それが継承です。
このコードだと名前とメールアドレスだけですが、実際のアプリになると名前のふりがな、年齢、住所、お支払い情報、電話番号…など、項目が大量に増えますよね。
もし extends で継承せず、Userクラスとは別に VIP用・BAN用のクラスをそれぞれゼロから作ると…
- 同じ項目を何度も書くことになる
- 項目を1つ追加・修正するたびに、全部のクラスを直さないといけない
- どこか1か所の修正漏れでバグが生まれる
といった問題が一気に出てきます。
そこで、継承で
- 共通部分は親クラスにまとめる
- 違う部分だけを子クラスで上書き・追加する
という形にしておくと、あとから仕様が変わっても、修正がとても楽になります。
外部連携(他のサービスとつながる)
ここまでは自分のプログラムの中だけで完結する処理 を一通り学んできました。
ですが、実際のWebサービスやアプリは自分のプログラムだけで完結することはほとんどありません。
たとえば、こんな機能を見たことはありませんか?
- ログイン時に「Googleでログイン」
- 支払いで「クレジットカード決済」
- 地図の表示(Googleマップ)
- 天気情報・株価・為替レートの取得
- LINEやSlackへの通知
これらはすべて、自分のプログラムが、外部のサービスと通信して情報をやり取りしているという仕組みで動いています。
このように他のサービスやシステムとつながって処理を行うこと を外部連携 と呼びます。
一般的に外部連携は、API(Application Programming Interface/アプリケーション・プログラミング・インターフェース)
と呼ばれる仕組みを通して行われます。
API(サービスの窓口)
APIは、他のサービスに「これをください」とお願いするための窓口です。
例えるなら、APIは自動販売機のボタンのようなものです。
- ボタンを押したら、飲み物が出てくる
- ボタンの裏側、自販機の仕組みは知らなくていい
- 決められた押し方を守らないと動かない
プログラムも同じで、「決められた方法でAPIを呼ぶ」と、外部サービスから決められた情報が返ってきます。
しかし、呼び方を間違えると、エラーになって何も返ってきません。
正しい呼び方はあなたが使いたい任意のAPIサービスの公式サイトなどに載っていることが多いですが、それを読んでも何が間違っているのか分からないこともよくあります。
そんな時のために、次の章でデバッグの考え方を知っておきましょう。
