プログラミング

ピカチュウから学ぶオブジェクト指向 〜クラス継承編〜 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"...

 

注目の記事

ナンパしてたら独立できた「人間力の鍛え方」
フリーランス
コミュニケーション能力,ナンパ
ナンパしてたら独立できた「人間力の鍛え方」

  経験談から、人間力を鍛える方法をご紹介します。 今回は「ナンパ」がテーマです。なので、少し男性目線の内容になります。 女性の方は、「男性はこうやって考えている人もいるんだ」といった参考にしてください。   ナンパなんて、と思う人もいるでしょう。 ハラスメント規制も強くなる現代では、安易な...

フォームはもう古い?サイトのCVRを高くするチャットシステムとは
マーケティング
CVR,ECショップ
フォームはもう古い?サイトのCVRを高くするチャットシステムとは

  サイトのコンバージョン率を上げたい お問い合わせフォームから連絡が来ない   ちょっとWebサイトやネットショップを立ち上げても中々思うような結果につながらない時代になりました。数多くのサイトが出回っていることはもちろん、ユーザーの閲覧頻度が増えて目が肥えているというのも大きな理由の1...

ブログ収益化の道!挫折ポイントの回避方法を徹底解説【アドセンス合格は通過点、意外な収益ポイントとは】
ライティング
Google AdSense,ブログ
ブログ収益化の道!挫折ポイントの回避方法を徹底解説【アドセンス合格は通過点、意外な収益ポイントとは】

  ノマドワークや副業としてブログ単体で稼げるようになりたいと考えている人は多いですが、その大半は挫折してしまいます。 アドセンスの合格までに辿りつけなかったり、合格したは良いものの思うように伸びずに諦めてしまうというのがほとんどです。 実は、そのアドセンスに対する考え方自体が間違いであり...

20代の独立が成功のカギ【学生→フリーランス・起業は危険です】
フリーランス
フリーランス,独立,起業
20代の独立が成功のカギ【学生→フリーランス・起業は危険です】

  終身雇用のほとんどが崩壊している今、学生の頃から独立や起業を考えている人は多いですが、安易な決断は危険です。 独立するには早すぎるのも良いとは言えず、また遅すぎることもそれなりにリスクです。 SNSやメディアでも学生起業などが騒がれていますが、それに影響されてしまうのはかなり危険なことです...

進化アニメーション 後編 PHPポケモン 60
プログラミング
PHP,PHPポケモン,ポケモン
進化アニメーション 後編 PHPポケモン 60

ポケモンの進化演出 前回に続いて、ポケモンの進化演出を実装していきます。バックエンドの処理はざっと説明をしたので、今回はフロントエンド(JavaScript)側の処理を作成していきましょう。   進化画面は新しく設けたので、こちらにもバトル画面で使っているメッセージ用JSを作成していきます。処理自体はほとん...

ポケモン入れ替え編 PHPポケモン 83
プログラミング
PHP,PHPポケモン,ポケモン
ポケモン入れ替え編 PHPポケモン 83

ポケモンの入れ替え 複数ポケモンの所有、そして並び替えの機能が整ったので、いよいよバトルでのポケモン交代機能を実装します。ポケモンがバトル中に交代する方法は大きく分けて以下の4つです。 プレイヤー操作による交代 ひんしによる交代 相手ポケモンの技による交代 味方ポケモンの技による交代 ...

非公開ディレクトリ画像表示編 PHPポケモン 91
プログラミング
PHP,PHPポケモン,ポケモン
非公開ディレクトリ画像表示編 PHPポケモン 91

非公開ディレクトリの画像を表示する 今回は、β版に向けての取り組みの1つとして、表示させる画像のアクセス先を非公開ディレクトリに変更します。 現在は公開ディレクトリ(Public)内のAssetsフォルダ内に配置していますが、これをルート直下においているStorageに移動させるのが目的となります。   gifのbas...

get_template_partで引数を渡す方法(WordPress5.5以降)
プログラミング
PHP,WordPress
get_template_partで引数を渡す方法(WordPress5.5以降)

WordPress5.5へのバージョンアップで、大きく機能が追加されました。中には変更に戸惑っている人もいるかも知れませんが、個人的にはエンジニアの要望を大きく取り入れて自由度がアップした印象があります。 今回はその中でも、多くの方が待ち望んでいた「get_template_part」の変更点についてご紹介します。 ge...

カテゴリ

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 独立 神戸 福祉 秘密鍵 翻訳 自己啓発 英語 見積書 計算機 読書 起業 迷惑メール 配列 銀の弾丸 集客 雑学力