プログラミング

ピカチュウから学ぶオブジェクト指向 〜クラス継承編〜 2

PHP PHPポケモン オブジェクト指向 ポケモン
ピカチュウから学ぶオブジェクト指向 〜クラス継承編〜 2

 

ピカチュウから学ぶオブジェクト指向の第2弾オブジェクトの継承についてです。

前回作成したピカチュウクラスを使用するので、もし基礎的な内容を学習したい人は、以下の記事を参考にしてください。

ピカチュウから学ぶオブジェクト指向 〜入門編〜 1 ピカチュウから学ぶオブジェクト指向 〜入門編〜 1

オブジェクト指向とは  オブジェクト指向プログラミング https://ja.wikipedia.org/wiki/オブジェクト指向プログラミング オブジェクト指向プログラミングとは、互いに密接な関連性を持つデータとメソッドをひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定...

 

オブジェクトの継承が理解できれば、複雑で規模の大きなシステムを構築することができるようになります。また、重複する記述が減らせることで、保守性なども格段に向上して作業負担も軽減されるため、ぜひこの機会に覚えておきましょう。

 

 

オブジェクトの継承とは

 

オブジェクトの継承(PHP.net

 

継承するということは、子となるクラスが親クラスのメソッドやプロパティを使用できるようにすることを意味します。前回作成したピカチュウクラスで考えてみましょう。

<?php
// ピカチュウ
class Pikachu
{

    private $name = 'ピカチュウ';
    public $nickname;
    private $move = [
        'でんきショック',
        'なきごえ',
    ];
 
    // クラス呼び出し時(インスタンス作成時)に自動で最初に実行される処理
    public function __construct($nickname=null)
    {
        $this->nickname = $nickname ?? $this->name;
    }
 
    // 正式名称を取得する
    public function getName()
    {
        return $this->name;
    }
 
    // 覚えている技の一覧を取得する
    public function getMove()
    {
        return $this->move;
    }
 
}

 

ニックネームを付ける機能や、名前や技の一覧を取得するというメソッドは、他のポケモン(ヒトカゲやゼニガメ等)でも同じくできなければなりません。しかし、これをポケモンを作るたびに準備するのは大変ですね。初代だけでも151匹分必要になります。

現在はクラス内の記述も少ないので問題ありませんが、よりゲームに近づけるとなれば更に多くの機能が必要になりますし、もし一部変更しなければならないようなことになれば、151匹分修正をかける必要があるのです。

 

そうならないためにも、共通して使える機能は親クラス上に記述して、そのクラスを継承して各ポケモンで使用できるようにします

 

 

「ポケモン」クラスを作成(親クラス)

 

ピカチュウの親となるのはどういったクラスでしょうか?

細かくカテゴライズしていけば、より良い継承先が見つかるかも知れませんが、大きな区分で見れば「ポケモン」というカテゴリに属しています。

 

では、Pokemonというクラスを新しく作成しましょう。

<?php
// ポケモン
class Pokemon
{
 
    protected $nickname;
   
    protected function setNickname($nickname)
    {
        $this->nickname = $nickname ?? $this->name;
    }
 
    // 正式名称を取得する
    public function getName()
    {
        return $this->name;
    }
   
    // ニックネームを取得する
    public function getNickname()
    {
        return $this->nickname;
    }
 
    // 覚えている技の一覧を取得する
    public function getMove()
    {
        return $this->move;
    }
 
}

 

他のポケモンでも共通する、ニックネームのプロパティ($nickname)正式名称を取得するメソッド(getName)技の一覧を取得するメソッド(getMove)をピカチュウのクラスから移動してきました。

ピカチュウのコンストラクタで実行していたニックネームを付ける処理は、setNicknameとして新しくメソッドを作成しました。ニックネームのプロパティもポケモンクラスに移動させたので、こちらも取得用のメソッドとしてgetNicknameを作成しています。

※アクセス修飾子のprotectedについては後ほど解説します

 

 

クラスを継承する

 

ポケモンというクラスを継承するためには、子に当たるPikachuクラスにその旨を記述する必要があります。ピカチュウクラスまでを含めたコード全体を見てみましょう。 

<?php
// ポケモン
abstract class Pokemon
{
 
    protected $nickname;
   
    protected function setNickname($nickname)
    {
        $this->nickname = $nickname ?? $this->name;
    }
 
    // 正式名称を取得する
    public function getName()
    {
        return $this->name;
    }
   
    // ニックネームを取得する
    public function getNickname()
    {
        return $this->nickname;
    }
 
    // 覚えている技の一覧を取得する
    public function getMove()
    {
        return $this->move;
    }
 
}

// ピカチュウ
class Pikachu extends Pokemon
{
  
    protected $name = 'ピカチュウ';
    protected $move = [
        'でんきショック',
        'なきごえ',
    ];
 
    // クラス呼び出し時(インスタンス作成時)に自動で最初に実行される処理
    public function __construct($nickname=null)
    {
        $this->setNickname($nickname);
    }
 
}
 
$pikachu = new Pikachu;
echo $pikachu->getNickname();
 
$pikachu1 = new Pikachu('ピカイチ');
echo $pikachu1->getNickname();

 

echoでの出力結果は以下の通りです。 

# 出力結果
ピカチュウ
ピカイチ

 

引数でニックネームを指定しなければ「ピカチュウ」、指定すれば「ピカイチ」と問題なく出力されていますね。

 

では、1つずつ確認してみましょう。まずはピカチュウのクラスからです。

class Pikachu extends Pokemon

 

クラス名の横に、新しくextends Pokemonという記述が追加されました。これがPokemonというクラスを親として継承するという意味になります。

 

次にコンストラクタ内の部分を確認してみましょう。

public function __construct($nickname=null)
{
    $this->setNickname($nickname);
}

 

親(Pokemon)が持つニックネームの書き込み用メソッド(setNickname)を使用しています。親の持つメソッドは、自クラスが持つメソッドを使用するように$this->メソッド(orプロパティ)と記述すれば呼び出すことができます

 

次にポケモンのクラスを見てみましょう。

abstract class Pokemon

 

classの前に新しくabstractと追加されました。これはクラスの抽象化です。

 

親クラスであるポケモン(Pokemon)を、ピカチュウのようにインスタンス化(実体化)されてしまっては困りますよね。ポケモンというポケモンは存在しないので当然です。そうならないために用意されているのがクラスの抽象化(abstract)です。これを付与することで、継承元(親クラス)としてだけ使用できるようになります。ポケモンのクラスは、あくまでピカチュウなどに共通するメソッドやプロパティを管理するためだけの親クラスでなければならないのです。

 

 

アクセス修飾子(protected

 

他にも変更されたポイントがあります。それがアクセス修飾子であるprotectedです。

ピカチュウクラス内のnameプロパティについて見てみましょう。

protected $name = 'ピカチュウ';

 

こちらは前回privateにしていました。理由は、外部からアクセスされて別のものに変更されてしまっては困るからです。ですがprivateにしてしまうと、ピカチュウクラス内からでしかアクセスが出来ません

 

ポケモンクラスを見てみましょう。

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

 

正式名称を取得するための「getName」というメソッドでピカチュウクラス内のnameプロパティにアクセスしています。もしprivateであれば、親クラスのポケモンクラスからもアクセスが出来ません。

外部からアクセスされては困る、しかし親クラスなど継承先や継承元からはアクセス出来なければ困る、そんな都合の良い制限をかけるために準備されたのが「protected」なのです。

他にも、setNicknameなどのメソッドに対してもprotectedが用いられています。メソッドについても、外部からのアクセスは困るが、クラス内では有効可したい場合にはprotectedをつけて同じような制限を設けることが可能です。

 

クラスの継承を使うようになれば、publicprotectedprivateの3つを使い分ける必要があります。それぞれどのような時に使用するかを考えながら、適切なアクセス制限を設けるようにしておきましょう。

  • public
    クラス内、クラス外のどこからでもアクセスが可能
  • protected
    同じクラス及び子クラスからアクセスが可能
  • private
    同じクラス内からのみアクセスが可能

 

 

技を覚えさせる

 

それでは新しく増設した継承クラスであるPokemon新しいメソッドを追加してみましょう。今回は「技を覚えさせる」という機能を増設します。どのポケモンでも技を新しく覚えていくことができますね。そのため、これはピカチュウのクラスなどではなく、親となるポケモンのクラスへ記述します。

// 技を覚えさせる
public function setMove($move)
{
    $this->move[] = $move;
    // 技が4つを超過していれば、最初の技を削除
    if(count($this->move) > 4){
        unset($this->move[0]);
        // 採番
        $this->move = array_values($this->move);
    }
}

 

setMoveというメソッドを新しく追加しました。これは外部からアクセスして使用するためpublicになります。

引数で技を指定して、それを新たにmoveプロパティ内にセットします。ポケモンのゲームでは技を覚えていられる最大数が4つなので、それを超過していれば一番上から消していきます。

 

それでは新しく「10万ボルト」「でんこうせっか」「かみなり」という3つの技を追加してみましょう。いかがコード全体図になります。

<?php
// ポケモン
abstract class Pokemon
{
 
    protected $nickname;
   
    protected function setNickname($nickname)
    {
        $this->nickname = $nickname ?? $this->name;
    }
 
    // 正式名称を取得する
    public function getName()
    {
        return $this->name;
    }
   
    // ニックネームを取得する
    public function getNickname()
    {
        return $this->nickname;
    }
 
    // 覚えている技の一覧を取得する
    public function getMove()
    {
        return $this->move;
    }
   
    // 技を覚えさせる
    public function setMove($move)
    {
        $this->move[] = $move;
        // 技が4つを超過していれば、最初の技を削除
        if(count($this->move) > 4){
            unset($this->move[0]);
            // 採番
            $this->move = array_values($this->move);
        }
    }
 
}

// ピカチュウ
class Pikachu extends Pokemon
{
  
    protected $name = 'ピカチュウ';
    protected $move = [
        'でんきショック',
        'なきごえ',
    ];

    // クラス呼び出し時(インスタンス作成時)に自動で最初に実行される処理
    public function __construct($nickname=null)
    {
        $this->setNickname($nickname);
    }
 
}
 
$pikachu = new Pikachu;
$pikachu->setMove('10万ボルト');
$pikachu->setMove('でんこうせっか');
$pikachu->setMove('かみなり');
 
var_export($pikachu->getMove());

 

$this->getMove()の出力結果は以下の通りです。

# 出力結果
array (
  0 => 'なきごえ',
  1 => '10万ボルト',
  2 => 'でんこうせっか',
  3 => 'かみなり',
)

 

順番に3つの技が追加されました。4つを超過したので、一番上にあった「でんきショック」が消えています。期待通りの結果ですね。

 しかしこのままでは、ピカチュウが覚えられないような技を追加出来てしまいますし、技が重複してしまう可能性があります。

 

これでは困りますので、重複チェックと覚えられる技の制限を加えましょう。まずは覚えられる技のリストをピカチュウのクラスに追記します。

// ピカチュウ
class Pikachu extends Pokemon
{
  
    protected $name = 'ピカチュウ';
    protected $move = [
        'でんきショック',
        'なきごえ',
    ];
    protected $move_list = [
        'でんきショック',
        'なきごえ',
        '10万ボルト',
        'かみなり',
        'でんこうせっか',
    ];
 
    // クラス呼び出し時(インスタンス作成時)に自動で最初に実行される処理
    public function __construct($nickname=null)
    {
        $this->setNickname($nickname);
    }
 
}

 

覚えられる技はポケモンによって異なります。なので、これはポケモンクラスではなく各ポケモンのクラスに対して割り振ります。また、外部からアクセスして変えられてしまっては困るので、外部からは不可、継承クラスからはアクセスが可能なprotectedを付与しておきましょう。

 

次に、覚えられる技と重複チェックをポケモンクラス内のsetMoveメソッドへ追記します。

// 技を覚えさせる
public function setMove($move)
{
    // 重複チェック
    if(in_array($move, $this->move, true)){
        echo $move.'はすでに覚えています';
        return;
    }

    // 覚えられる技かチェック
    if(!in_array($move, $this->move_list, true)){
        echo $move.'は覚えられません';
        return;
    }

    $this->move[] = $move;

    // 技が4つを超過していれば、最初の技を削除
    if(count($this->move) > 4){
        unset($this->move[0]);
        // 採番
        $this->move = array_values($this->move);
    }
}

 

まずは重複チェックです。

if(in_array($move, $this->move, true)){
    echo $move.'はすでに覚えています';
    return;
}

 

in_arrayを使用して、現在覚えている技($this->move)に覚えようとしているものが存在しているかをチェックしています。もしあればエラーメッセージを出力して、その時点で処理を終了させるためにreturnを使います。

 

次に覚えられる技かチェックをします。

if(!in_array($move, $this->move_list, true)){
    echo $move.'は覚えられません';
    return;
}

 

同じようにin_arrayを使用して$this->move_list内に技があるかどうかをチェックしています。今回はリスト内に技がなければエラーメッセージを出す必要があるので、!in_arrayで逆の判定をしています。こちらも同じように、エラーメッセージを出せばreturnで処理を終了させます。

 

それでは確認してみましょう。

<?php
// ポケモン
abstract class Pokemon
{
 
    protected $nickname;
  
    protected function setNickname($nickname)
    {
        $this->nickname = $nickname ?? $this->name;
    }
 
    // 正式名称を取得する
    public function getName()
    {
        return $this->name;
    }
   
    // ニックネームを取得する
    public function getNickname()
    {
        return $this->nickname;
    }
 
    // 覚えている技の一覧を取得する
    public function getMove()
    {
        return $this->move;
    }
   
    // 技を覚えさせる
    public function setMove($move)
    {
        // 重複チェック
        if(in_array($move, $this->move, true)){
            echo $move.'はすでに覚えています';
            return;
        }

        // 覚えられる技かチェック
        if(!in_array($move, $this->move_list, true)){
            echo $move.'は覚えられません';
            return;
        }

        $this->move[] = $move;

        // 技が4つを超過していれば、最初の技を削除
        if(count($this->move) > 4){
            unset($this->move[0]);
            // 採番
            $this->move = array_values($this->move);
        }
    }
 
}
 
// ピカチュウ
class Pikachu extends Pokemon
{
  
    protected $name = 'ピカチュウ';
    protected $move = [
        'でんきショック',
        'なきごえ',
    ];
    protected $move_list = [
        'でんきショック',
        'なきごえ',
        '10万ボルト',
        'かみなり',
        'でんこうせっか',
    ];
 
    // クラス呼び出し時(インスタンス作成時)に自動で最初に実行される処理
    public function __construct($nickname=null)
    {
        $this->setNickname($nickname);
    }
 
}
 
$pikachu = new Pikachu;
$pikachu->setMove('かえんほうしゃ');
$pikachu->setMove('でんきショック');
$pikachu->setMove('10万ボルト');
 
var_export($pikachu->getMove());

 

出力結果は以下の通りです。

# 出力結果
かえんほうしゃは覚えられません
でんきショックはすでに覚えています
array (
  0 => 'でんきショック',
  1 => 'なきごえ',
  2 => '10万ボルト',
)

 

最初にセットしようとした「かえんほうしゃ」はピカチュウが覚えられる技のリストに含まれていませんので、エラーメッセージが返ってきました。次にセットしようとした「でんきショック」はすでに覚えているので、同様にエラーメッセージが返ってきました。

最後にセットした10万ボルトは、覚えられるリスト内にも含まれており、現在は覚えていないので無事覚えることができました。

 

このようにして、共通して使いたい機能は継承クラスとして準備することで、他のポケモンを用意した際には独自の設定を追加するだけで同じように使用することができるのです。

 

 

まとめ

 

いかがだったでしょうか。

今回は「【PHP】ピカチュウから学ぶオブジェクト指向 〜クラス継承編〜」をご紹介しました。

オブジェクト(クラス)の継承ができるようになれば、管理はよりしやすくなり、大幅な変更などが生じても比較的対応がしやすくなります。また、ポケモンのように種類が多いようなものを管理するためには向いています。

PHPを学習中の方で、クラスを使ったシステムやサイトづくりを考えている人は、ぜひ参考にしてくださいね。

 

第3回はコチラ(レベルシステムの導入)

ピカチュウから学ぶオブジェクト指向 〜レベルシステム導入編〜 3 ピカチュウから学ぶオブジェクト指向 〜レベルシステム導入編〜 3

  大人気?シリーズ「ピカチュウから学ぶオブジェクト指向」、今回はレベルシステムの導入編です。   第1回(基礎編)、第2回(クラス継承編)で作成したPokemonとPikachuのクラスを使用するので、最初から学習したい人はぜひご参考ください。 [shortcode_url_og url="https://s-yqual.com/blog/1035"...

 

注目の記事

フリーランスが見積書を作るときに押さえておきたい3つのポイント+α
フリーランス
フリーランス,仕事依頼,独立,見積書
フリーランスが見積書を作るときに押さえておきたい3つのポイント+α

  仕事の依頼がきたけど、どれぐらいの金額を提示すればいいかわからない   駆け出しのフリーランスや、これから独り立ちしようとしている人に多い悩みです。 今回はそういった方のために「フリーランスが見積書を作るときに押さえておきたい3つのポイント+α」についてご紹介します。     時給...

毎日継続をするためのコツ
雑記
毎日継続をするためのコツ

定期的にコラムを書きたくなるので、今回は「毎日継続をするためのコツ」というテーマで自分が意識していることや、感じたことを書き綴っていきます。 決して開発や業務で追われていたり、PHPポケモンの大幅見直しを迫られているわけではありません。   毎日継続するために  ブログや学習など、毎日継続...

PHPポケモン「レベルアップ進化編」9
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「レベルアップ進化編」9

  PHPポケモン(旧:ピカチュウから学ぶオブジェクト指向)も第9回目となりました。前回GitHubよりコードを配布したので、これから学習しようと考えている人は、ぜひ参考にしてください。   最初からコードの内容について学びたい人は、ぜひ記念すべき第1回から順を追って取り組んでみてください。   ...

人員配置計算機〜放課後等デイサービス・児童発達支援〜
プログラミング
JavaScript,児童デイ,児童発達支援,放課後等デイサービス,福祉,計算機
人員配置計算機〜放課後等デイサービス・児童発達支援〜

最近はずっとPHPポケモン開発にかかりっきりでしたが、そろそろ「役立つもの」を作りたくなったので、思いつきで作ってみました。 もちろん「汎用性」のあるものは、既に世の中に存在しているため、ありそうでなさそうなニッチなものを攻めてみます。   そんな中、今回挑んだのは「人員配置計算機」です。 ※実際に...

売れるECサイトになるために必要な3つの戦略
マーケティング
ECショップ,コンサルティング
売れるECサイトになるために必要な3つの戦略

  ECサイトで全く売れない・・・   ネットショップのオープンが手軽で安価になり、クレジット決済も主流の今ECサイトを立ち上げるお店も増えてきました。 しかし期待感とは裏腹に、思ったような売上が出なかったり、お客さんが1人も獲得できていないケースも少なくありません。   今回はそういった「...

Laravel7系でTraitのmakeコマンドを作成する方法
プログラミング
artisan,Laravel,Linux,PHP,Trait
Laravel7系でTraitのmakeコマンドを作成する方法

Laravel7がリリースされて、さっそくそれを使った開発の機会がやってきましたので、使用頻度の高いものをまとめていきたいと思います。 5系や6系の情報は多く出回っていますが、6系がLTSということもあって7系の情報は少なめですね。   今回は「Laravel7系でTraitのmakeコマンドを作成する方法」をご紹介します...

ネコにこばん編 PHPポケモン73
プログラミング
PHP,PHPポケモン,ポケモン
ネコにこばん編 PHPポケモン73

ネコにこばんとは 初代ポケモンでは、基本的にトレーナーとのバトルでしかお金を増やすことができず、もし手持ち金が0円の状態で金が必要なイベントが発生すると詰んでしまうという隠された落とし穴がありました。 ですが、初代でも唯一トレーナー意外からお金を得る方法があります。それが「ネコにこばん」という...

独立してから心がけていること【社会人時代と比較して】
フリーランス
フリーランス,独立
独立してから心がけていること【社会人時代と比較して】

  今回は自分が独立してから心がけていることの中から、ある程度上手くいっていることや、オススメできるようなことを簡単に感想付きでまとめてみました。 社会人時代と比較しながらの内容なので、これからフリーランスで生きていこうと思っている人や、社会人という生活にストレスを感じている人は是非参考に...

カテゴリ

SEO対策 イベント デザイン ネットワーク ビジネスモデル フリーランス プログラミング マーケティング ライティング 動画編集 雑記

タグ

5G Adobe AfterEffects AI ajax amazon Animate api artisan atom Automator AWS Bluetooth CSS CVR description EC-CUBE4 ECショップ ESLint Facebook feedly foreach function Google Google AdSense Honeycode htaccess HTML IEEE 802.11ax Illustrator Instagram IoT JavaScript jQuery jQuery UI keyword LAN Laravel Linux MacBook MAMP meta MLM MySQL NoCode note OS OSI参照モデル Paypal Photoshop PHP phpMyAdmin PHPポケモン PremierePro rss SEO SEO対策 Sequel Pro Skype SNS SSH Symfony TCP/IP title Toastr Trait Twig Twitter UCC V系 WAN WebSub Wi-Fi wiki Windows WordPress XAMPP xml Xserver YouTube YouTuber Zoom アーティスト アウトプット アクセス層 アニメーション アフィリエイト イーブイ インターネット インプット エンジニア オブジェクト指向 お金配り クリック単価 クリック数 コミュニケーション能力 コロナ コンサルティング サムネイル システムエンジニア スタートアップ スタイルシート スパム データベース ディープフェイク デザイナー デザイン テレワーク ナンパ ニュース ネットワークモデル ノマドワーク バナー ピカチュウ ビジネス フィード フリーランス ブロガー ブログ プログラマー プログラミング プログラミング学習 プログラミング教育 プロトコル ホームページ制作 ポケモン マークアップ マーケティング メール リモートワーク レンダリング 三井住友 三宮 仕事依頼 児童デイ 児童デイサービス 児童発達支援 公開鍵 初心者 助成金 勉強法 営業 広告 広告収入 必勝マニュアル 放課後等デイサービス 朝活 楽天 深層学習 無線LAN 独立 神戸 福祉 秘密鍵 翻訳 自己啓発 英語 見積書 計算機 読書 起業 迷惑メール 配列 銀の弾丸 集客 雑学力