プログラミング

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

 

注目の記事

【Laravel】論理削除対応型existsバリデーションの実装方法
プログラミング
Laravel,PHP
【Laravel】論理削除対応型existsバリデーションの実装方法

  Laravelでは多くのバリデーションが提供されていますが、論理削除を使用している場合はそのままでは使えないものが複数あります。 今回は紐付けをする際に存在チェックで使用するexistsのソフトデリート対応のバリデーションを実装する方法をご紹介します。     カスタムバリデーションの追加   存...

SEが心がけるべき3つの習慣
プログラミング
Automator,JavaScript,エンジニア,システムエンジニア,プログラマー,プログラミング
SEが心がけるべき3つの習慣

  ネット社会、在宅ワークが主流になってきた今、SEという仕事に憧れを頂いている人は多くなりました。 単価の良さも、魅力の一つです。そして、技術が普及してきたことにあわせて、便利なソフトやアプリが簡単に手に入るようになり、一昔前と比べると技術の習得も容易になりました。   しかし、多くの人が...

ブログで生活するための7つの道のり 〜収益化と拡散の方法教えます〜
ライティング
Facebook,Google AdSense,Twitter,ノマドワーク
ブログで生活するための7つの道のり 〜収益化と拡散の方法教えます〜

  ブログで生活したい   毎日数時間、ブログを書くだけで生きていける、そんな夢のような生活を実現させたいと思い描く人は多いですが、簡単なことでは有りません。 ですが、やらなければいけないことがわかっていれば、収益化するのは簡単です。   今回は「ブログで生活するための7つの道のり」をテ...

独立するならWordPress理解しておけばOK!プログラミングでフリーランスはこれ一つで成り立ちます
プログラミング
PHP,WordPress,フリーランス,独立
独立するならWordPress理解しておけばOK!プログラミングでフリーランスはこれ一つで成り立ちます

  プログラミングでフリーランスを目指すには、どの言語始めればいいの?   プログラミングの学習を始めたのに、それをどう活かせばよいか分からず、いざフリーランスで活動しようと思ってもイメージできずに断念してしまう人は多いです。 言語にも向き不向きがあるため、フリーランスとして活動するために向...

XserverにSequel ProでSSH接続する方法を4ステップでわかりやすく解説
ネットワーク
phpMyAdmin,Sequel Pro,SSH,Xserver,データベース,公開鍵,秘密鍵
XserverにSequel ProでSSH接続する方法を4ステップでわかりやすく解説

  AWSなどが注目される中、Xserver(エックスサーバー)は操作やセットアップが簡単で、ポートフォリオや業務、個人ブログ(WordPess)で使用している方に需要が高いサービスです。 そしてMacのPCを使っている方はデータベースの管理ツールとして、無料で使えるSequel Proが人気があり、多くのユーザーが使用し...

連続の技習得編 オブジェクトをセッションへ格納 PHPポケモン57
プログラミング
PHP,PHPポケモン,ポケモン
連続の技習得編 オブジェクトをセッションへ格納 PHPポケモン57

セッション経由でのオブジェクト引き継ぎ 技習得の処理が整ってきたので、ここで連続技習得・連続レベルアップ時にも問題なく動作するように作り込んでいきます。ですが、現状のモーダルをレスポンスやメッセージと同様に、そのまま引き継いだとしてもエラーが発生します。 その原因がセッション経由でのオブジェク...

レベニューシェアとは?利益報酬・共同事業に潜む罠
フリーランス
レベニューシェアとは?利益報酬・共同事業に潜む罠

  レベニューシェアという言葉を聞いたことがありますか?   ビジネスの世界にいる人なら、意味は知らなくてもやったことがある方が意外と多いはずです。特にフリーランスの人や、プログラミングやデザインといったスキルを持っている人はレベニューシェアでは重宝されるため多い傾向があります。ここ最近...

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

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

カテゴリ

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