プログラミング

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

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

オブジェクト指向とは 

オブジェクト指向プログラミングとは、互いに密接な関連性を持つデータとメソッドをひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。

 

上記引用文で「なるほど!わかった!」となった方は、本記事を読む必要はありません

 

プログラミング、特にオブジェクト指向の説明になれば専門用語がかなり多く出てくるため、初心者がただ読んだだけでは理解できないケースがほとんどです。

今回はそんなオブジェクト指向について、よりわかりやすく理解を深め「便利じゃん!」となるように、日本の代表的ゲームである「ポケモン」のピカチュウの力を借りてご説明します。もしポケモンのゲームをやったことがない、全く知らないという人は、ブラウザをバックして別のオブジェクト指向について説明が書かれている記事を参考にするか、一度初代ポケモンをプレイしてから出直してください。

  

ピカチュウを作る 

オブジェクト指向では、まずクラスを作成することから始まります。今回はピカチュウをという存在を定義するために、Pikachuというクラスを作成します。 

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

 

これでピカチュウが出来上がりました。中身は空っぽですので、これから1つずつ理解しながら詰め込んでいきます。

 

オブジェクト指向では、まずこのようにクラスを作ることで、ピカチュウという存在そのものを定義します。ゲームを進めていく中で、ピカチュウは1匹だけではありませんよね(ややこしいのでピカチュウ版は除きます)。好きな人は、2匹、3匹と捕まえるかも知れません。さらに、技構成全く同じではなかったり、能力値やレベルも個体によってばらつきが出ます。

しかし中身が違っていても、その全てが「ピカチュウ」で有ることには代わりありません。その「ピカチュウ」という存在事態を定義するのがクラスなのです。

  

個体を作成(インスタンス)

 クラスを作成しても、それは「ピカチュウ」という存在事態が定義されたに過ぎず、実体はありません。これは初期の「ミュウ」という存在で考えてみるとわかりやすいかも知れません。

初代のポケモンが発売された当初、「ミュウ」という存在自体は確かにありました。しかし、ゲーム上で捕まえることが出来ず(バク・裏技を除く)、実体はどこにも有りませんでした。しかし、イベントで配布するということによって、初めてその実体が確認され、ユーザーの元に届き、ミュウを使うことができるようになりました。この実体こそが「インスタンス」です。

 

それでは、ピカチュウの実体(インスタンス)を作ってみましょう。

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

$pikachu = new Pikachu;

 

new クラス名」とすることで、ピカチュウのインスタンスを作成することができます。$pikachuという変数に代入しているので、$pikachuはピカチュウです。もちろんピカチュウは1匹限りの存在ではないので、複数匹呼び出すことが出来ます。 

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

// トキワの森
$pikachu1 = new Pikachu;
$pikachu2 = new Pikachu;
$pikachu3 = new Pikachu;
$pikachu4 = new Pikachu;
$pikachu5 = new Pikachu;

 

$pikachu15までの5匹分のインスタンスを作成しました。この全てがピカチュウですが、それぞれは別個体です。もし$pikachu1に10万ボルトという技を覚えさせたとしても、それに連動して$pikachu23も同じように覚えることはありません。

 

名前の設定(プロパティ)

 では、ピカチュウのクラスに情報を入れていきましょう。

まず最初に必要になるのは名前です。正式名称として、ピカチュウという名前をクラス内に設定しましょう。 

<?php
// ピカチュウ
class Pikachu
{
    public $name = 'ピカチュウ';
}

$pikachu = new Pikachu;
echo $pikachu->name;

 

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

ピカチュウ

 

期待した通りの結果が出力されましたね。

それでは、クラス内に追加した部分を見みましょう。

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

 

クラス内では変数が定義できます。これをプロパティ呼びます。ここに値を代入することで、ピカチュウのクラス内では$name($this->name)をピカチュウとして扱うことが出来ます。

※クラス内の$nameの手前に付けたpublicについては後ほど解説します

 

インスタンス化(実体化)したピカチュウから名前を教えてもらうためには、クラス内に定義したプロパティにアクセスする必要があります。

$pikachu = new Pikachu;
echo $pikachu->name;

 

ピカチュウというインスタンスが格納されている$pikachuから、->を使用してnameを取り出しています。こうしておけば、インスタンスさえ呼び出されていれば、いつでも名前を確認することが可能です。

 

ニックネームをつける(コンストラクタ)

 ポケモンは捕まえた際に、ニックネームを付けることができます。同じポケモンを複数体育てるのであれば、その判別のためにもニックネームがなければひと目で見分けが付きません。今回はポケモンを捕まえる過程が無いので、インスタンスを作成した時点でニックネームを設定できる仕様にしましょう。そのために使うのがコンストラクタです。

<?php
// ピカチュウ
class Pikachu
{
   
    public $name = 'ピカチュウ';
    public $nickname;
    
    public function __construct($nickname=null)
    {
        if(is_null($nickname)){
            $this->nickname = $this->name;
        }else{
            $this->nickname = $nickname;
        }
    }
  
}
 
$pikachu = new Pikachu('ピカイチ');
echo $pikachu->nickname;

 

echo $pikachu->nicknameの出力結果は以下の通りです。

ピカイチ

 

クラスの使い方に慣れていない方は、そろそろややこしくなってきましたね。でも安心してください。1行ずつしっかり理解していけば問題有りません。

 

まず、クラス内にニックネームを格納するためのプロパティを準備しました。

public $nickname;

 

初期状態ではニックネームは設定されていないので、プロパティだけを宣言します。そして、次に出てきている関数が今回の注目ポイントです。

public function __construct($nickname=null)

 

クラス内で使える変数(プロパティ)があるように、クラス内で使える関数もあります。これをメソッドと言います。メソッドについては次項で詳しく解説します。

今回クラス内で使っている__constructは特別なものです。なぜなら、このクラスをインスタンス化(実体化)した際、自動的に動いてくれるからです。クラスの呼び出し部分から動きを確認してみましょう。

$pikachu = new Pikachu('ピカイチ');

 

先程の呼び出し方と少し変わって、new Pikachuのあとにカッコと値がありますね。これは引数です。ピカチュウというクラスを呼び出す際に、第1引数として「ピカイチ」という値を指定しました。

クラスが呼び出されると、先程説明したようにクラス内にある__constructが自動で動きます。第1引数で指定された「ピカイチ」という値は、ここで受け取ることができます

__constructの引数として、$nickname=nullが指定されています。これも関数の引数と同じで、もしクラスを呼び出す際にニックネームの指定がなければ、nullを初期値として格納します。今回は「ピカイチ」という値が指定されているので、$nicknameにはピカイチが格納されました

では、__constructの中身を確認してみましょう。

if(is_null($nickname)){
    $this->nickname = $this->name;
}else{
    $this->nickname = $nickname;
}

 

ここで1つ複雑なポイントを解消しておきましょう。

__constructで引数で受け取る値を格納する変数を$nicknameとしました。しかし、クラス内ではプロパティとして同じように$nicknameが宣言されています。これは名称が同じであっても、同じものではありません。なぜなら、クラス内で定義したプロパティは、$nicknameとしては使用せずに、$this->nicknameというように使用するからです。

 

$thisはクラスのことを指しています。今回であればPikachuというクラスです。クラス内のプロパティである$name$nicknameにアクセスする場合は$this->name$this->nicknameとしなければなりません。そのため、__construct内の$nicknameは別物なのです。更にこの引数として受け取った$nicknameは、プロパティと違って__construct内でしか使用できません

 

上記を踏まえて、先程の処理を1行ずつ確認見ていきましょう。

if(is_null($nickname)){

 

引数で受け取った$nickname(ピカイチ)をis_nullで判定して条件分岐(if)しています。今回はピカイチという値が引数で指定され、$nicknameに格納されているので、is_nullfalse(否)となり、else内の処理に入ります。

}else{
    $this->nickname = $nickname;
}

 

else内では$this->nickname$nicknameを代入しています。$this->nicknameはピカチュウクラスのプロパティです。初期値が設定されていないため、現在は何も格納されていません。そこに代入する$nicknameには引数で受け取った「ピカイチ」が格納されています。$this->nickname(空)に$nickname(ピカイチ)を代入することで、nicknameというプロパティに「ピカイチ」という値をセットしているのです。

 

上記の処理がクラスを呼び出した時点「$pikachu = new Pikachu(‘ピカイチ‘);」で行われています。そのため、インスタンス化(実体化)した$pikachuからニックネームを取り出すと、ピカイチという値が取得できるのです。

echo $pikachu->nickname;
# 出力結果
ピカイチ

 

では、クラスを呼び出す際に引数を指定しなかった場合を見てみましょう。

<?php
// ピカチュウ
class Pikachu
{
   
    public $name = 'ピカチュウ'; #
    public $nickname;
    
    public function __construct($nickname=null)
    {
        if(is_null($nickname)){
            $this->nickname = $this->name;
        }else{
            $this->nickname = $nickname;
        }
    }
  
}
 
$pikachu = new Pikachu;
echo $pikachu->nickname;
# 出力結果
ピカチュウ

 

これは、__construct内のif文でis_null($nickname)true(正)を返したからです。

if(is_null($nickname)){
    $this->nickname = $this->name;

 

is_null内の$nicknameは引数の値が格納されていましたね。指定されていなければ初期値「$nickname=null」として設定されたnullが入っているので、if文内の「$this->nickname = $this->name」が実行されます。

nicknameのプロパティに、nameのプロパティ(ピカチュウ)がセットされています。ポケモンのゲームでもニックネームを指定しなければポケモンの正式名称がセットされるので、仕様としては同じになりました。

 

このように、__constructはクラスを呼び出したとき、最初に自動的に実行されるメソッド(関数)だということです。合わせて、プロパティと変数との違い($this->nickname$nickname)についても、ざっくりで構いませんので覚えておきましょう。

 

最後に__construct内をPHP7仕様に簡略化しておきます。

※処理内容はほとんど変わりませんので、is_nullを使った方法の方がわかりやすい人はそちらを参考にしてください。null合体演算子の場合は空文字(”)を許可してしまいますが、今回はそこまで厳密にしていしないものとします

<?php
// ピカチュウ
class Pikachu
{
   
    public $name = 'ピカチュウ';
    public $nickname;
    
    public function __construct($nickname=null)
    {
        $this->nickname = $nickname ?? $this->name;
    }

}

 

null合体演算子について内容を詳しく知りたい人は、以下の記事を参考にしてください。

【PHP7】はてな2つとは??Null合体演算子を使った存在チェック 【PHP7】はてな2つとは??Null合体演算子を使った存在チェック

  PHP Notice:  Undefined variable: 変数名 in /***/***.php on line 2   PHPで変数や対象のキーが存在しない配列を使おうとすれば、上記のようなエラーが吐き出されますね。PHP5.6までは初期値を設定したり、issetで判定したりしてそれを回避していましたが、2015年末にリリースされたPHP7からは新しくN...

 

技を取得(メソッド)

 ポケモンといえば技を習得できますね。初代ピカチュウの場合、最初は「でんきショック」と「なきごえ」という技を覚えています。これはピカチュウという存在事態に共通していることなので、クラスへ設定します。

private $move = [
    'でんきショック',
    'なきごえ',
];

 

今回はpublicではなくprivateでプロパティを準備しました。こちらも後ほど解説します。

 

次に、技の一覧を取得するために、クラス内で使用できる関数(メソッド)を作成します。

// 覚えている技の一覧を取得する
public function getMove()
{
    return $this->move;
}

 

__constructは特別なメソッドでしたが、自ら用途に合わせて使いたい関数をクラス内に準備することができます。これがメソッドです。

PHPでは変数や関数を必要に応じて作ることができますよね。これを、そのクラス内で使う用として準備するものがメソッドになります。

 

では、技を増設した処理と出力結果を確認してみましょう。

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

$pikachu = new Pikachu;
var_export($pikachu->getMove());
# 出力結果
array (
  0 => 'でんきショック',
  1 => 'なきごえ',
)

 

ピカチュウの技一覧が取得できましたね。では、今回追加したgeMoveというメソッドを確認してみましょう。

// 覚えている技の一覧を取得する
public function getMove()
{
    return $this->move;
}

 

内容はいたって簡単です。getMoveを呼び出せば、技の一覧を返す「retrun $this->move」という内容です。$this->moveには「でんきショック」と「なきごえ」を配列として入れているので、それを返却してくれています。

 

メソッドの呼び出し方法も、プロパティと同じように->を使用します。

$pikachu->getMove()

 

インスタンスが作成されていれば、そのクラス内で準備しているメソッドを呼び出すことができるのです。

 

アクセス修飾子

 それでは気になっていたpublicprivateについて、最後にまとめておきましょう。

プロパティやメソッドの手前についていたこれらは、アクセス修飾子と言います。PHPでは以下の3種類が用意されています。

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

※protectedについては今回無視しましょう。混乱しないためにも、まずはpublicとprivateを押さえて置けば十分です。

 

publicは、どこからでもアクセスが可能なプロパティ、メソッドだということを宣言します。例えば、$pikachu->nameでピカチュウという値が取得できるのもpublic $nameと宣言しているおかげです。

それに対して、先程$moveprivateと宣言しました。その結果、nameとは違い$pikachu->moveでは取得することができません。

<?php

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

    // クラス呼び出し時(インスタンス作成時)に自動で最初に実行される処理
    public function __construct($nickname=null)
    {
        $this->nickname = $nickname ?? $this->name;
    }
 
    // 覚えている技の一覧を取得する
    protected function getMove()
    {
        return $this->move;
    }
  
}
 
$pikachu = new Pikachu;
$pikachu->move;
# 出力結果
PHP Fatal error:  Uncaught Error: Cannot access protected property Pikachu::$move in ...

 

これでは困るため、技の一覧を取得するためのgetMoveというメソッドを作成したのです。

 

しかし、ここで1つ疑問が残ります

結局取得できるようにするのであれば、privateではなくpublicで良いのでは?

 

そう思いますよね。

しかし、それではいけません。なぜなら、アクセスができるということは、取得だけではなく「書き込み」も出来てしまうからです。

<?php
# moveのアクセス修飾子をpublicに変更した場合

// ピカチュウ
class Pikachu
{
    public $move = [
        'でんきショック',
        'なきごえ',
    ];
 
    // 覚えている技の一覧を取得する
    public function getMove()
    {
        return $this->move;
    }
  
}
 
$pikachu = new Pikachu;
$pikachu->move = [
    'かえんほうしゃ',
    'ハサミギロチン',
];
var_export($pikachu->getMove());
# 出力結果
array (
  0 => 'かえんほうしゃ',
  1 => 'ハサミギロチン',
)

 

 

 

このように、簡単に外部から書き込みが出来てしまうことはエラーや予期せぬ結果を招く危険性があります。そうならないためにも、アクセス修飾子を使って制御する必要があります。

 

これを踏まえて、他のアクセス修飾子も見直したクラスがこちらです。

<?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;
    }
  
}

 

ニックネーム(nickname)は変わってしまっても大きく支障がありませんので、publicのままにしていますが、正式名称(name)は変えられると一大事ですのでprivateへ変更しました。取得出来ないままでも困るので、技と同様にgetNameというメソッドで取得できるようにしています。__constructはpublicしか指定できませんので、変更は不要です。

 

このように、外部から書き込みしても良いか、呼び出しが出来ても良いかなどを考えながらアクセス修飾子を設定していきます。

 

まとめ

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

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

今回取り上げたピカチュウのように、決まった存在を定義する際にはクラスを使うと管理がしやすくなり、開発がスムーズになります。

オブジェクト指向への理解がまだまだ甘いこれからPHPを本格的に学習しようと考えている方は、ぜひ参考にしてくださいね。

 

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

  ピカチュウから学ぶオブジェクト指向の第2弾はオブジェクトの継承についてです。 前回作成したピカチュウクラスを使用するので、もし基礎的な内容を学習したい人は、以下の記事を参考にしてください。 [shortcode_url_og url="https://s-yqual.com/blog/1035" title="" target="yqual_sub"]   オブジェク...

 

PHPポケモンのプレイはコチラ

 

注目の記事

PHPポケモン「バトルシステム実装編〜タイプ相性の判定〜」デモ&配布有り 19
プログラミング
jQuery,PHP,PHPポケモン,ポケモン
PHPポケモン「バトルシステム実装編〜タイプ相性の判定〜」デモ&配布有り 19

  システムを組むなら、仕様書や設計書はしっかり作りましょう。   ということで、またまたフォルダ移動やページ分けなどを見えないところでやりました。正直説明すると全く進まなくなりそうなので、改修部分は必要最低限にします。 結論、説明しません。(コード配布するので許してください)   そして今...

PHPポケモン「野生ポケモン遭遇編」18
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「野生ポケモン遭遇編」18

  PHPポケモンが第18回にしていよいよバトルの第一歩、野生ポケモンとの遭遇編に突入です。 新しいコントローラーの作成と、バトル画面の作成、そしてポケモンデータの受け渡しなどを中心にご紹介します。   バトル画面の実装  ポケモンのゲームでも、野生ポケモンが現れるとバトル画面へ移管し...

ピカチュウから学ぶオブジェクト指向 〜ステータス導入編〜 6
プログラミング
PHP,PHPポケモン,オブジェクト指向,ポケモン
ピカチュウから学ぶオブジェクト指向 〜ステータス導入編〜 6

  PHPをピカチュウ(ポケモン)から学ぶ大人気コーナー、第6回目は「ステータス機能の導入編」です。   前回(第5回)で終了段階でのサンプルコードを公開しているので、もし本記事から始める人はぜひそちらを参考にしてください。    ※お詫び   調べたところによると、ポケモンの経験...

レポート(試験)編 PHPポケモン 94
プログラミング
PHP,PHPポケモン,ポケモン
レポート(試験)編 PHPポケモン 94

今回の内容は、あくまで試験的なものとなります。実際にそのままの仕組みで導入するかは未定です。 ※セーブ機能の実装自体は予定しております   また、今回はセーブするための仕組みの部分にのみにフォーカスを当てています。非公開ディレクトリやパーミッション等による最低限の対応は施していますが、試験的にア...

トレーナー戦編 バトルシステムへの追加 PHPポケモン 98
プログラミング
PHP,PHPポケモン,ポケモン
トレーナー戦編 バトルシステムへの追加 PHPポケモン 98

トレーナー戦闘の追加 前回トレーナー情報を作成したので、今回はその情報をバトルシステムへ組み込んでいきます。 現在、野生ポケモンとの戦闘では「battle」という値actionの値で受け取っています。同じサービス内で分岐を作ると複雑になってしまうので、battle_trainerという新しい分岐を使ってサービス分けをし...

会話スキルに自信がない人必見!会議やミーティングで失敗しないコツとは
雑記
Skype,Zoom
会話スキルに自信がない人必見!会議やミーティングで失敗しないコツとは

  話下手なので会議で置物状態 Zoomミーティングは発言しづらい 会議の時間が退屈で無駄   そんな悩みや不満を抱えている方はいませんか? 確かに会議は退屈ですし、話下手な人からすれば嫌な時間の1つかも知れませんね。 ですが、立ち回りのポイントを3つ押さえておくだけで、無駄・退屈だと感じて...

PHPポケモン「技クラス実装編」14
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「技クラス実装編」14

  前回せっかくBootstrapを使って見た目を整えたにも関わらず、ビューポートの記述が抜けているという凡ミスが発覚したので修正しています。 サーセン。   今回のPHPポケモンでは本格的な技システムを実装していきます。技システムが整えば、皆さん期待のバトルシステムも間近です。セキュリティ面やファイル構成...

引き継ぎ考慮のメッセージID重複回避編 PHPポケモン 58
プログラミング
PHP,PHPポケモン,ポケモン
引き継ぎ考慮のメッセージID重複回避編 PHPポケモン 58

今回のPHPポケモンでは内部の作り込みをしていきます。見た目への反映は無いので、プレイを楽しみにしている人や、ポケモンが好きで毎日チェックしてくれているような人は、ブラウザをバックしてもらって問題ありません。   それでは、前々回辺りから保留にしていた「メッセージIDに重複回避対策」についてです。 &...

カテゴリ

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

タグ

5G Adobe AfterEffects AI ajax amazon Animate api artisan atom Automator AWS Bluetooth CSS CVR description EC-CUBE4 ECショップ ESLint Facebook feedly foreach fortify function Google Google AdSense Honeycode htaccess HTML IEEE 802.11ax Illustrator Instagram IoT JavaScript jetstream jQuery jQuery UI keyword LAN Laravel Linux MacBook MAMP meta MLM MySQL NoCode note OS OSI参照モデル Paypal Photoshop PHP phpMyAdmin PHPポケモン PremierePro rss 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 独立 神戸 福祉 秘密鍵 翻訳 自己啓発 英語 見積書 計算機 認証 読書 起業 迷惑メール 配列 銀の弾丸 集客 雑学力