プログラミング

ピカチュウから学ぶオブジェクト指向 〜トレイト編〜 4

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

 

ピカチュウから学ぶオブジェクト指向の第4弾は「トレイト(trait)の活用」についてです。更に、レベルシステムを導入すれば欠かせない経験値システムも合わせて実装します。

第3回からの続きとなりますので、もし前回をまだ見ていない人は是非ご参考ください。

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

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

 

それでは今回もピカチュウと一緒に、楽しくプログラミング、オブジェクト指向を学習しましょう。

 

 

トレイト(trait)とは

 

 

トレイトは、PHP のような単一継承言語でコードを再利用するための仕組みのひとつです。 トレイトは、単一継承の制約を減らすために作られたもので、 いくつかのメソッド群を異なるクラス階層にある独立したクラスで再利用できるようにします。 トレイトとクラスを組み合わせた構文は複雑さを軽減させてくれ、 多重継承や Mixin に関連するありがちな問題を回避することもできます。

 

トレイトはクラスと似ていますが、トレイトは単にいくつかの機能をまとめるためだけのものです。 トレイト自身のインスタンスを作成することはできません。 昔ながらの継承に機能を加えて、振る舞いを水平方向で構成できるようになります。 つまり、継承しなくてもクラスのメンバーに追加できるようになります。

 

 

だそうです。簡単にまとめるなら

継承しなくても使えるよ!インスタンスも作れないよ!なクラス

 といったところでしょう。

汎用性のあるメソッドをまとめておくイメージです。今回作っているようなポケモンのクラスでも使え、アイテムというクラスでも使えるようなメソッドも場合によっては必要になります。そういったものを毎回書かなくても良いようにまとめて置くのがトレイトの本来の使い方です。

 

 

トレイトの活用

 

前回(第3回)でファイルを分割しましたが、それでも記述量は多くなってきました。特にポケモンクラス内のメソッドが回数を重ねるごとに増えていきます。そこで、今回はトレイト(trait)を使って管理をします。

 

現在ポケモンクラス内にあるメソッドでは「get〜」という取得用のメソッドと、「set〜」という値を格納するようのメソッドで構成されています。なので、get関係set関係をそれぞれまとめて置くように「SetTrait」と「GetTrait」を作成しましょう。作成箇所は以下の通りです。

/Trait/GetTrait.php
/Trait/SetTrait.php

 

それではそれぞれのファイル内を見ていきましょう。

 

Get関係の格納トレイト(/Trait/GetTrait.php
<?php
trait GetTrait
{
 
    /**
    * 正式名称を取得する
    * @return string
    */
    public function getName()
    {
        return $this->name;
    }
 
    /**
    * ニックネームを取得する
    * @return string
    */
    public function getNickname()
    {
        if(empty($this->nickname)){
            return $this->name;
        }
        return $this->nickname;
    }
 
    /**
    * 覚えている技の一覧を取得する
    * @return array
    */
    public function getMove()
    {
        return $this->move;
    }
 
    /**
    * 現在のレベルを取得する
    * @return integer
    */
    public function getLevel()
    {
        return $this->level;
    }
 
}

 

Set関係の格納トレイト(/Trait/SetTrait.php
<?php
trait SetTrait
{
    /**
    * ニックネームを付ける
    * @return string
    */
    public function setNickname($nickname)
    {
        if(empty($nickname) || mb_strlen($nickname, 'UTF-8') > 5){
            echo 'ニックネームは1〜5文字で入力してください';
            return;
        }
        $this->nickname = $nickname;
    }
 
    /**
    * レベルをセットする
    * @return void
    */
    protected function setLevel()
    {
        // 初期レベルからランダムで値を取得
        $key = array_rand($this->default_level);
        $this->level = $this->default_level[$key];
    }
 
    /**
    * 初期技をセットする
    * @return void
    */
    protected function setDefaultMove()
    {
        foreach($this->level_move as list($level, $move)){
            if($level <= $this->level){
                // 現在レベル以下の技であれば習得
                $this->setMove($move);
            }else{
                // 現在レベルを超えていれば処理終了
                break;
            }
        }
    }
 
    /**
    * 技を覚える
    * @return string
    */
    public function setMove($move)
    {
        $this->move[] = $move;
        if(count($this->move) > 4){
            unset($this->move[0]);
        }
    }
 
}

 

それぞれgetsetのメソッドを移動してきました。それではトレイトの宣言部分について確認しましょう。

trait GetTrait

 

クラスとの大きな違いは最初の行にあります。クラスの場合はclassと宣言してからクラス名をつけますが、トレイトの場合はtraitと宣言してトレイト名をつけます。その他の記述方法はほとんど同じですが、宣言が違うということを覚えておきましょう。そして最初の説明でも述べたように、トレイトはインスタンス化(実体化)することができません

 

 

トレイトの読み込み

 

次に、クラスに対してトレイトを読み込む方法を見ていきましょう。今回はどちらもポケモンクラス内で使用していたメソッドなので、ポケモンクラス上で作成した2つのトレイトを読み込みます。

 

ポケモンのクラス(/Class/Pokemon.php
<?php
 
require_once('Trait/SetTrait.php');
require_once('Trait/GetTrait.php');
 
// ポケモン
abstract class Pokemon
{
    use SetTrait;
    use GetTrait;
 
    /**
    * ニックネーム
    * @return string(min:1 max:5)
    */
    protected $nickname;
 
    /**
    * 現在のレベル
    * @var integer(min:2 max:100)
    */
    protected $level;
 
    /**
    * 覚えている技
    * @var array
    */
    protected $move = [];
 
}

 

require_onceで使用するトレイトファイルを読み込みクラス内でトレイトの使用を宣言しています。

use SetTrait;
use GetTrait;

 

注意点は、useをクラス内で使用するということです。現在はまだ紹介していませんが、名前空間やオートローダーを使用するとクラスの前にuseをつけて必要ファイルを読み込みます。それに対して、トレイトの使用宣言はクラス内で行います。

 

これでポケモンのクラスで各トレイトに割り当てたメソッドが使用できるようになりました。ポケモンのクラスで使用できるということは、それを継承しているピカチュウのクラスでも呼び出すことができます。出力用ファイル(index.php)に記述して確認してみましょう。

 

出力用ファイル(index.php
<?php

require_once('Class/Pikachu.php');

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

?>

<p>ニックネーム:<?=$pikachu->getNickname()?></p>

 

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

# 出力結果
 
ピカチュウをゲットした
 
ニックネーム:ピカイチ

 

 

経験値システムの導入

 

レベルシステムにとって欠かせないのが経験値システムです。その初期準備として、初期経験値の計算と次のレベルアップに必要な経験値の算出を実装します。

そのために、まずポケモンの経験値の仕組みを見てみましょう。 

 

今回はリンク先の「経験レベルと必要経験値の換算表」という部分を参考にします。ポケモンによって異なるようですが、今回は最も単純なピカチュウの経験値タイプでもある「100万型」を実装します。

 

100万型経験値の計算方法は以下の通りです。

必要経験値 = Lv^3

 

もう少しわかりやすく表現すると

必要経験値 = レベル x レベル x レベル

 

上記の式が成り立ちます。PHP(5.6以降)であれば**演算子が使えるので、今回作成しているポケモンシステムであれば、以下の式で現在のレベルに必要な経験値を算出します。

$this->level ** 3

 

 

デフォルト経験値

 

ポケモンは捕まえた時点で、そのレベルに応じた経験値を所有していなければなりません。そのために、経験値を格納しておくプロパティ、デフォルト経験値の算出用メソッド、現在の経験値を取得するメソッドの3つを用意します。

 

  1. 経験値を格納するプロパティ
    ポケモンのクラス(/Class/Pokemon.php)
  2. デフォルトの経験値を算出するメソッド
    Set格納トレイト(/Trait/SetTrait.php) 
  3. 現在の経験値を取得するメソッド
    Get格納トレイト(/Trait/GetTrait.php)

 

ポケモンのクラス(/Class/Pokemon.php
/**
* 経験値
* @var integer
*/
protected $ex_point;

 

Set格納トレイト(/Trait/SetTrait.php
/**
* 初期経験値をセットする
* @return void
*/
protected function setDefaultExPoint()
{
    $this->ex_point = $this->level ** 3;
}

 

Get格納トレイト(/Trait/GetTrait.php
/**
* 現在の経験値を取得する
* @return integer
*/
public function getExPoint()
{
    return $this->ex_point;
}

 

setDefaultExPointのメソッドは、ポケモンを捕まえた時点で実行される必要がありますので、ピカチュウのクラスのコンストラクタで実行しましょう。

 

ピカチュウのクラス(/Class/Pikachu.php
/**
* インスタンス作成時に実行される処理
*/
public function __construct()
{
    $this->setLevel();
    $this->setDefaultExPoint();
    $this->setDefaultMove();
    echo 'ピカチュウをゲットした';
}

 

setDefaultExPoint内でレベルのプロパティ($this->level)が使用されています。なので実行するタイミングはsetLevelのあとでなければなりません

 

では、ピカチュウのインスタンスを作成して、経験値を実行ファイルで確認してみましょう。

 

実行ファイル(/index.php
# 出力結果(1回目)
 
ピカチュウをゲットした
 
現在のレベル:8
現在の経験値:512
# 出力結果(2回目)
 
ピカチュウをゲットした
 
現在のレベル:9
現在の経験値:729

 

換算表で確認してみると、レベル8では512レベル9では729となっているため正常に算出出来ていることがわかります。 

 

これで、初期経験値の設定は完了です。

 

 

次のレベルまで

 

ポケモンの経験値で気になるのは、現在の値よりも次のレベルまでに必要な値です。なので、次のレベルまでの値を算出するメソッドをGet格納トレイトに追加します。

 

Get格納トレイト(/Trait/GetTrait.php
/**
* 次のレベルに必要な経験値
* @return integer
*/
public function getReqLevelUpExPoint()
{
    return ($this->level + 1) ** 3 - $this->ex_point;
}

 

次のレベルまでに必要な経験値の算出方法は以下の通りです。

次のレベルまでに必要な経験値

= 次のレベルで必要な経験値 現在の経験値

 

現在の経験値は$this->ex_pointに格納されています。次のレベルで必要な経験値は以下の式で算出できます。

次のレベルで必要な経験値

= (現在のレベル + 1)の3乗

 

1列にまとめているので複雑な式に見えてしまうかも知れませんが、やっていることは至って単純です。算出式が、以下の通りです。

($this->level + 1) ** 3 - $this->ex_point

 

それでは出力結果を確認してみましょう。

 

実行ファイル(/index.php
<?php

require_once('Class/Pikachu.php');

$pikachu = new Pikachu;

?>

<p>現在のレベル:<?=$pikachu->getLevel()?></p>
<p>現在の経験値:<?=$pikachu->getExPoint()?></p>
<p>次のレベルまでに必要な経験値:<?=$pikachu->getReqLevelUpExPoint()?></p>
# 出力結果
 
ピカチュウをゲットした
 
現在のレベル:7
現在の経験値:343
次のレベルまでに必要な経験値:169

 

現在の経験値(343)と次のレベルまでに必要な経験値(169)を足すと、レベル8で必要な経験値(512)になるので正常に出力されていることがわかります。

 

これで、次のレベルまでに必要な経験値の出力設定が完了です。

 

 

詳細の取得

 

機能が増えてくれば、一つずつ出力するのは一苦労です。なので、一気に詳細を出力できるようなメソッドを作成します。Get格納トレイトに以下を追加しましょう。

 

Get格納トレイト(/Trait/GetTrait.php
/**
* 詳細を取得する
* @return integer
*/
public function getDetails()
{
    return [
        '正式名称' => $this->getName(),
        'ニックネーム' => $this->getNickName(),
        '現在のレベル' => $this->getLevel(),
        '覚えている技' => implode(',', $this->getMove()),
        '現在の経験値' => $this->getExPoint(),
        'レベルアップに必要な経験値' => $this->getReqLevelUpExPoint(),
    ];
}

 ※配列キーに日本語が用いられることはほとんど有りませんが、今回はわかりやすさ重視のために日本語を使用しています。気になる人は値として格納してlistで取得するなどしてください

 

それでは返り値として準備された配列を見てみましょう。

return [
    '正式名称' => $this->getName(),
    'ニックネーム' => $this->getNickName(),
    '現在のレベル' => $this->getLevel(),
    '覚えている技' => implode(',', $this->getMove()),
    '現在の経験値' => $this->getExPoint(),
    'レベルアップに必要な経験値' => $this->getReqLevelUpExPoint(),
];

 

返却する内容は至って単純です。それぞれの取得用メソッドに見出しとなるキーを割り振っています。「覚えている技」は返り値が配列のため、そのまま文字列として出力できるようにimplodeを使用しています。 

 

それでは、出力結果を確認してみましょう。

 

実行ファイル(/index.php
<?php

require_once('Class/Pikachu.php');
 
$pikachu = new Pikachu;
$pikachu->setNickname('ピカイチ');
$details = $pikachu->getDetails();

?>
 
<?php foreach($details as $key => $val): ?>
<p><?=$key?>:<?=$val?></p>
<?php endforeach; ?>

 

ピカチュウをインスタンス化(実体化)させて、「ピカイチ」というニックネームをつけました。

詳細の取得メソッド(getDetails)は配列で返ってくるため、$detailsという変数に格納してforeachで見出し($key)と一緒に取り出しています。

 

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

# 出力結果
 
ピカチュウをゲットした
 
正式名称:ピカチュウ
ニックネーム:ピカイチ
現在のレベル:8
覚えている技:でんきショック,なきごえ
現在の経験値:512
レベルアップに必要な経験値:217

 

正常に取得できていますね。

一括取得のメソッドがあれば、すぐにインスタンスの中身が確認ができるため便利です。

 

 

まとめ

 

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

今回は「【PHP】ピカチュウから学ぶオブジェクト指向 〜トレイト編 & 経験値システム導入〜」をご紹介しました。

 

トレイト(trait)の使い方はプロジェクトによっても様々ですが、今回紹介したようにファイル内のメソッドを分割して管理するために用いることも可能です。継承する必要が無いため、複数のクラスで使いまわしするメソッド格納用として使えれば、より保守性も高まり管理手間が少なくなります。

※今回はあくまでトレイトの使い方の説明用として用いているので、それぞれのプロジェクトに合わせた使い方をしてください

 

PHPを学習中の方や、ポケモンやゲームづくりに興味がある人は、ぜひ参考にしてみてくださいね。

 

注目の記事

個人の時代で成功するための起業への3ステップ 〜新時代を生き抜くために〜
フリーランス
ビジネス,独立,起業
個人の時代で成功するための起業への3ステップ 〜新時代を生き抜くために〜

  起業ってどのタイミングですればいいかわからない・・・   令和時代での起業の考え方は、昭和や平成とは大きく変わっています。個人の時代と呼ばれる現代では、今までのようにリスクを背負って起業することは失敗の確率はより高く、オススメできません。   今回は、起業を志している人たちへ向けて私...

名刺は時代遅れ!?Googleの名刺検索「ピープルカード」とは
フリーランス
Google,SEO
名刺は時代遅れ!?Googleの名刺検索「ピープルカード」とは

  Googleが2020年8月よりインドでピープルカードの検索機能を開始しました。これがフリーランスや個人事業主、起業家などに対して営業ツールとして大きな影響をもたらすのでは無いかと期待されており、今後ビジネスにおける繋がりが大きく変化していくことも予想されます。   今回は、そんなGoogleの新し...

トレーナー戦編 トレーナー情報の作成 PHPポケモン 97
プログラミング
PHP,PHPポケモン,ポケモン
トレーナー戦編 トレーナー情報の作成 PHPポケモン 97

トレーナー戦 いよいよPHPポケモンでもトレーナー戦の実装に取り掛かっていきます。バトルシステム自体は野生ポケモンと同じですが、トレーナーバトルでは以下の項目が追加、または制限を設けることになります。 複数匹のポケモン 逃げられない 捕まえられない 賞金   複数匹のポケモン ざっくり...

レビューがアフィになる!?SNS式ECサイトとは【ビジネス企画書】
ビジネスモデル
ECショップ,SNS
レビューがアフィになる!?SNS式ECサイトとは【ビジネス企画書】

  多くの人が利用しているSNS 副業やフリーランスに人気なアフィリエイト   それぞれの良い点を上手く利用すれば、完成するビジネスはないか?と考えて思い浮かんだ企画です。 今回は「レビューがアフィになる!?SNS式ECサイトとは」について、新時代のショッピングモール式ネットショップの企画をご紹...

【脱初心者向けプログラミング学習】処理を追え!「今、変数には何が入ってる?」
プログラミング
HTML,PHP,プログラミング学習
【脱初心者向けプログラミング学習】処理を追え!「今、変数には何が入ってる?」

  初心者から中々抜け出せない 1から処理をかけない   そんな悩みを抱えたプログラミング学習者に向けて、「脱初心者のためのプログラミング学習」についてPHPを例にまとめました。 やり方自体は同じですので、他の言語をメインとしている人は自分の環境に置き換えながら学習して、初心者から抜け出しましょ...

できるやつの「雑学力」
雑記
勉強法,雑学力
できるやつの「雑学力」

  テレビのコメンテーター、討論番組の出演者で活躍するほとんどの人は物知りだ。 あなたも「よくそんなことまで知っているな」と思ったことはあるだろう。 現代で起業して成功し続ける人のほとんどが、常に新しい情報を取り入れている。 そして得た情報に対して、歴史情報と照らし合わせ、自分なりの意見や解釈を...

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

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

捕獲処理実装編 PHPポケモン 80
プログラミング
PHP,PHPポケモン,ポケモン
捕獲処理実装編 PHPポケモン 80

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

カテゴリ

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