【PHP】オブジェクト指向を完全に理解した話【前編】
先日、会社の研修で軽い演習みたいなものをしました。
その時に出てきたのが『オブジェクト指向』、『継承』。
そういえば大学でやったなぁ。
オブジェクト指向で設計した方が、効率いいんでしょ?
程度にしか理解してませんでした。
そこで今一度ちゃんと復習をしようとした結果、完全に理解しました。
ここでいう『完全に理解した』の定義はここにある通りです。
(完全に理解した < 何もわからない < チョットデキル)
なのでここで自分が学んだオブジェクト指向をまとめたいと思います。
(長くなってしまったので前編・後編で分けました。)
オブジェクト指向の概念
まず、オブジェクト指向はなんのために使うのか、というと
設計図を定めて、さらにパーツごとにまとめたら量産するときに楽だよね
ということです。
そこで、プログラムのコードもパーツごとに分けて作って拡張性を良くしよう(拡張するときに楽)と言う話。
では次に、PHPのコードで実際にどうすることがオブジェクト指向なのかをみていく。
クラス/オブジェクト
クラスは設計図の中でも、一番外側の大枠部分と言うイメージ。
オブジェクト指向をガンプラで例えると、クラスは『ガンダム』とか『ザク』とかそう言う分類。
クラスを実体化するとオブジェクトになる。
<?php
class Zaku {} // クラスを宣言(まだザクは実物として生成されていない)
$test = new Zaku; // 変数に new を使って代入することで初めて実物になる。
echo gettype($test); // 型はobject型。
プロパティ/メソッド
なんか小難しく言ってるけど、
プロパティ → 変数
メソッド → 関数
みたいな認識でおk。
<?php
class Zaku {
public $color = 'green'; // プロパティ
private $name = 'zaku'; // プロパティ
protected $speed = 1; // プロパティ
function buildArms() { // メソッド
echo $this->color;
}
function buildLegs() { // メソッド
echo $this->name;
}
function buildHead() { // メソッド
echo($this->speed);
}
}
プロパティ(変数)を宣言する時は、プロパティの前に
『public / private / protected』のどれかを定義してあげなければいけません。
- public … どこから呼んでも使用することができる
- private … そのクラス内でしか使用することができない
- protected … そのクラス内 or サブクラス内(後述)で使用することができる
それぞれこのような特徴があります。
ピンとこないので、↓で見てみましょう。
class Zaku {
public $color = 'green'; // プロパティ
private $name = 'zaku'; // プロパティ
protected $speed = 1; // プロパティ
function buildArms() { // メソッド
echo $this->color;
}
function buildLegs() { // メソッド
echo $this->name;
}
function buildHead() { // メソッド
echo($this->speed);
}
}
$test = new Zaku;
$test->buildArms(); // 結果:green
$test->buildLegs(); // 結果:zaku
$test->buildHead(); // 結果:1
echo $test->color; // 結果:green (public)
echo $test->name; // 結果:エラー (private)
echo $test->speed; // 結果:エラー (protected)
↑でまず、echoするためにプロパティの取り出し方を見てみます。
- クラス内でプロパティを取り出す場合は $this->[プロパティ名] (例:7行目)
- クラス外でプロパティを取り出す場合は $[オブジェクト名]->[プロパティ名] (例:22行目)
次に、echoの結果を見てみると
- $test->buildArms(); ではクラス内で呼び出しているので表示される
- $test->buildLegs(); ではクラス内で呼び出しているので表示される
- $test->buildHead();ではクラス内で呼び出しているので表示される
- echo $tess->color;はpublicで、クラス外で呼び出しているので表示される
- echo $test->name;はprivateで、クラス外で呼び出しているので表示されない
- echo $test->speed;はprotectedで、クラス外で呼び出しているので表示されない
となります。
継承
次に、先ほど作ったクラスを拡張したい時があります。
例えば、ザクを拡張してシャア専用ザクを作りたい、とします。
その時は↓のように継承というものを使って拡張することができます。
class Zaku {
public $color = 'green'; // プロパティ
private $name = 'zaku'; // プロパティ
protected $speed = 1; // プロパティ
function buildArms() { // メソッド
echo $this->color;
}
function buildLegs() { // メソッド
echo $this->name;
}
function buildHead() { // メソッド
echo($this->speed);
}
}
class SyaZaku extends Zaku { // 追加部分
function highSpeed() {
echo $this->speed; // 結果:1
$this->speed = 3;
echo $this->speed; // 結果:3
}
}
$sya = new SyaZaku;
$sya->highSpeed();
$sya->buildArms(); // 親クラス(継承元)のメソッドも使える
$sya->buildLegs(); // 結果:エラー(privateはサブクラス(継承先)で使えない)
echo $sya->speed; // 結果:エラー
extendsを使うことで継承ができます。
SyaZakuはZakuを継承しているので、Zakuが持っていたプロパティ/メソッドは引き継がれた状態です。
なのでSyaZaku内で宣言していませんが、27,28行目でbuildArms()とbuildLegs()が使えています。
また、例えば19行目で$speedをechoしていますが、Zakuが持っていた 1 を引き継いでいます。
しかし20行目のSyaZakuクラス内で$speedを変更したので、21行目では3になります。
ここで注意なのが、extendsで継承したプロパティ/メソッドは全て引き継がれる…と思いきや
privateと宣言していたものは引き継ぐことができません。
publicと、protectedと宣言していたものは引き継ぐことができます。
当然ですが、protectedと言っていた$speedは、ZakuとSyaZakuの外側では見ることができません。
コンストラクタ
いちいち関数を呼び出さなくても、オブジェクトを生成したときに自動で実行してくれる機能があります。
それがコンストラクタです。
今回では、コンストラクタを使ってシャアザク生成時に色を赤に変えます。
class Zaku {
public $color = 'green'; // プロパティ
private $name = 'zaku'; // プロパティ
protected $speed = 1; // プロパティ
function buildArms() { // メソッド
echo $this->color;
}
function buildLegs() { // メソッド
echo $this->name;
}
function buildHead() { // メソッド
echo($this->speed);
}
}
class SyaZaku extends Zaku {
function highSpeed() {
echo $this->speed; // 結果:1
$this->speed = 3;
echo $this->speed; // 結果:3
}
function __construct() { // 追加部分
$this->color = 'red';
echo $this->color;
}
}
$sya = new SyaZaku; // 結果:red
コンストラクタの宣言の仕方が特殊で、__(アンダーバー2つ)をつけて宣言します。
このような特殊なメソッドをマジックメソッドと言います。
これは今は名前だけ覚えておけば良いと思います。
また、コンストラクタはオブジェクト生成時に実行されるので30行目で生成するだけで red と表示されます。
まとめ
オブジェクト指向の中で、これだけは知っておきたいという必要最低限のものをまとめてみました。
ですがまだ他にも知っておくべきことがあるのですが長くなってしまうため、続きは後編として別の記事にしました。
よろしければ後編の方もお読みいただけると幸いです。

zawa1205
webフロントエンドエンジニア