プログラミング

ピカチュウから学ぶオブジェクト指向 〜入門編〜 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ポケモン 80
プログラミング
PHP,PHPポケモン,ポケモン
捕獲処理実装編 PHPポケモン 80

捕獲処理の作成 前回モンスターボールのクラスを作成したので、今回は捕獲判定までの一連の処理を仕上げていきます。サービス自体は他のアイテムと一緒にするためItemServiceを呼び出し、その中で使用されたアイテムを判断して分岐を作ります。   バトル中のアイテムサービス(/App/Services/Battle/ItemService.ph...

未経験からWeb系エンジニアとしてフリーランスになる現実的な方法教えます【軌道に乗れば起業も可能】
フリーランス
エンジニア,フリーランス,プログラミング学習,独立,起業
未経験からWeb系エンジニアとしてフリーランスになる現実的な方法教えます【軌道に乗れば起業も可能】

  セカンドキャリアとしてプログラミングやデザインを学習したい   そう考えてスクールを受講したり、独学で始める人が増えていますが、そのほとんどが実らずに挫折してしまいます。 ですが、学習方法と経験の積み方や職の選び方さえ間違えなければ、技術を身につけてフリーランスとして活動することも難しく...

「諦めが上手い人」ほど成功する!正しい目標の立て方とは
雑記
PHP
「諦めが上手い人」ほど成功する!正しい目標の立て方とは

  「諦めたらそこで試合終了ですよ」   漫画の中でも有名なセリフですが、これからあなたは何を読み取りますか? 何か目標を達成するために努力が必要とされますが、その方法がわからずに試行錯誤したり、そもそも挑戦すらできずに終えてしまう人は多いのです。 努力をした人は、ほとんどがそれは結果的...

デザイン
サムネイル,デザイナー,バナー,広告
デザイナーにセンスは必要ない!誰でも作れるおしゃれなサムネイル

  「デザイナーになるためにはセンスが必要ですか?」   バナーづくりの小規模講習会を実施した際に、この質問した人がいました。 よくある質問なのですが、いつも決まって自分の回答は「NO」です。   実際に一流のデザイナーとして活躍するレベルまでいくには、確かにセンスと呼ばれているものが必要...

動画編集に役立つ基本的な考え方【Adobe AfterEffects】
動画編集
Adobe,AfterEffects,PremierePro,YouTube
動画編集に役立つ基本的な考え方【Adobe AfterEffects】

  YouTubeの人気に合わせて、動画編集の需要も高まってきましたが、その大変さから挫折してしまう人も続出しています。 動画編集は奥が深く、技術的な部分に関してはプロのクリエイターであっても自分がよく使うような一部しか把握していないのが普通であり、調べても該当する情報が出てきにくいということもあ...

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

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

PHPポケモン(α)第1回目の大型アプデ
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン(α)第1回目の大型アプデ

第1回目 大型アップデートについて 本日、PHPポケモンの大型アップデートをしました。 今回のアップデートには全体的なデザインチェンジが含まれているため、今まで遊んでくれていた人も、新鮮な気持ちで初められることができるはずです。   デザインについては、PHPを使った開発をしている人からすれば馴...

数字が増える毎日投稿テクニック【銀の弾丸はありません】
ライティング
YouTuber,ブロガー,銀の弾丸
数字が増える毎日投稿テクニック【銀の弾丸はありません】

  まずは以下のグラフを御覧ください。     私が管理しているYouTubeのチャンネルで、1日投稿ができない日がありました。 そうすると、その日がいつなのかすぐわかるぐらい露骨に視聴者数が減ったのです。それほど、毎日投稿することは結果に大きく影響します。   今回は、本ブログで何度も切り口を変え...

カテゴリ

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