プログラミング

グローバル&ヘルパー関数編 PHPポケモン 61

PHP PHPポケモン ポケモン
グローバル&ヘルパー関数編 PHPポケモン 61

進化や技習得、HPバーや経験値バーの演出ができているのに、なぜ状態異常の演出はされていないの?

 

そう感じている方が少なからずいるはずです。

現段階では、状態異常になっても次の画面に移管しなければ表示されません。これは、PHP側で内部処理は行われているが、メッセージに合わせた動的な変更がされていないからです。

 

実は、この実装を妨げている原因が「レスポンストレイト」なのです。

今回のPHPポケモンは、よりよいシステム構成にするための「グローバル関数」と「ヘルパー関数」の実装方法についてご紹介します。

 

グローバル関数

グローバル変数という名称はよく聞くかも知れませんが、グローバル関数という言葉にはあまり聞き馴染みがない人が多いはずです。なぜなら、あくまでこれは仮名称で、どこからでも呼び出せる関数ということを表現しているだけだからです。

 

例えば、tranJpという日本語置き換えの関数を序盤に実装しましたよね。これは、ページの最初に読み込んでおくことで、どこからでも呼び出すことが可能です。

これを、レスポンス(メッセージ・モーダルを含む)関係で活用できるようにするのが、今回のグローバル関数の目的です。

 

グローバル変数の活用

作成するグローバル関数と合わせて使いたいのが「グローバル変数」です。セッションやポストなどもグローバル変数(スーパーグローバル変数)ですが、今回はこれとは別のグローバル変数を用意します。

 

例えば、以下の例を見てみましょう。

<?php
$global = 'グローバル変数';
 
function test(){
    return $global;
}
 
var_dump(test());

 

上記のコードでは、test関数内で宣言している$globalは「見つかりません」となりエラーが吐き出されてしまいます。関数内では、あくまでその関数内で作成された変数や引数しか使うことができません。

 

ですが、これをグローバル宣言することで、testという関数内でも$globalを使うことができます。

<?php
$global = 'グローバル変数';
 
function test(){
    global $global;
    return $global;
}
 
var_dump(test());

 

関数内で、globalという宣言をして変数を記述します。こうすることで「この関数で使う$globalは、関数外で使っているglobalのことだよ」ということを知らせてやることができるのです。

 

レスポンスのクラス化と一元化

それでは、原因となっているレスポンストレイトについてです。

現在は、どのクラスでも活用できるようにトレイトとしてレスポンス関係を管理していましたが、こうすることでそれぞれのクラス内にレスポンスが含まれてしまうことになります。そのせいで、引き継ぎ処理などがややこしくなってしまい、混乱や機能制限を招く結果となっています。

なのでそれを解決するためにも、レスポンスはクラスとして用意することで、一元管理しましょう。

 

レスポンスクラス(/Classes/Response.php
<?php
class Response
{
    /**
    * メッセージの格納用
    * @var array
    */
    private $messages = [];
 
    /**
    * レスポンスデータの格納用
    * @var array
    */
    private $responses = [];
 
    /**
    * モーダルの格納用
    * @var array
    */
    private $modals = [];
 
    /**
    * メッセージIDの発行
    *
    * @return string
    */
    public function issueMsgId()
    {
        // IDを生成
        $id = 'msg'.substr(bin2hex(random_bytes(16)), 0, 16);
        // ユニークになるようにチェック
        while(in_array($id, $_SESSION['__message_ids'] ?? [], true)){
            $id = 'msg'.substr(bin2hex(random_bytes(16)), 0, 16);
        }
        $_SESSION['__message_ids'][] = $id;
        return $id;
    }
 
    /**
    * 全リセット
    *
    * @return void
    */
    public function resetResponsesAll()
    {
        $this->messages = [];
        $this->responses = [];
        $this->modals = [];
    }
 
    /**==================================================================
    * メッセージ関係の処理
    ==================================================================**/
    /**
    * メッセージの取得
    *
    * @return array
    */
    public function getMessages()
    {
        return $this->messages;
    }
 
    /**
    * メッセージの格納
    *
    * @param string|array $msg
    * @param mixed $param
    * @return array
    */
    public function setMessage($msg, $param=null)
    {
        if(empty($msg)){
            // 空の場合はスキップ
            return;
        }
        if(is_array($msg)){
            // 一括登録
            $this->messages = array_merge($this->messages, $msg);
        }else{
            // 単発登録
            $this->messages[] = [$msg, $param, ''];
        }
    }
 
    /**
    * アニメーション用の自動メッセージの格納
    *
    * @param mixed $param
    * @return array
    */
    public function setAutoMessage($param)
    {
        $this->messages[] = ['', $param, 'auto'];
    }
 
    /**
    * 空メッセージの格納
    *
    * @param string $param
    * @return array
    */
    public function setEmptyMessage(string $param='')
    {
        $this->messages[] = ['', $param, ''];
    }
 
    /**
    * メッセージの初期化
    *
    * @return void
    */
    public function resetMessage()
    {
        $this->messages = [];
    }
 
    /**
    * メッセージの最初のキーを取得
    *
    * @return void
    */
    public function getMessageFirstKey()
    {
        return array_key_first($this->messages);
    }
 
    /**
    * メッセージの最後のキーを取得
    *
    * @return void
    */
    public function getMessageLastKey()
    {
        return array_key_last($this->messages);
    }
 
    /**==================================================================
    * レスポンス関係の処理
    ==================================================================**/
    /**
    * 指定したレスポンステータの取得
    *
    * @param string|integer
    * @return mixed
    */
    public function getResponse($param)
    {
        if(isset($this->responses[$param])){
            return $this->responses[$param];
        }
    }
 
    /**
    * レスポンステータの全取得
    *
    * @return array
    */
    public function getResponses()
    {
        return $this->responses;
    }
 
    /**
    * レスポンステータの格納
    *
    * @param mixed $response
    * @param mixed $key
    * @return array
    */
    public function setResponse($response, $key=null)
    {
        if(empty($response)){
            // 空の場合はスキップ
            return;
        }
        if(is_null($key)){
            // キー指定無し
            if(is_array($response)){
                // $responseが配列の場合の処理
                $this->responses = array_merge($this->responses, $response);
            }else{
                // $responseが配列ではない場合の処理
                $this->responses[] = $response;
            }
        }else{
            // キー指定有り
            $this->responses[$key] = $response;
        }
    }
 
    /**
    * 指定されたプロパティをレスポンスにセット(出力)
    *
    * @return void
    */
    public function exportProperty(...$properties)
    {
        foreach($properties as $property){
            $this->setResponse($this->$property, $property);
        }
    }
 
    /**
    * レスポンステータの初期化
    *
    * @return void
    */
    public function resetResponse()
    {
        $this->responses = [];
    }
 
    /**==================================================================
    * モーダル関係の処理
    ==================================================================**/
    /**
    * モーダルテータの取得
    *
    * @return array
    */
    public function getModals()
    {
        return $this->modals;
    }
 
    /**
    * モーダル用テータの格納
    *
    * @param array $param
    * @param boolean $merge
    * @return array
    */
    public function setModal(array $param, bool $merge=false)
    {
        if(empty($param)){
            // 空の場合はスキップ
            return;
        }
        if($merge){
            // 結合(引き継ぎ)
            $this->modals = array_merge($this->modals, $param);
        }else{
            // モーダル格納
            $this->modals[] = $param;
            // モーダル起動時用のからメッセージをセット
            $this->messages[] = ['', '', ''];
        }
    }
 
    /**
    * モーダル情報の初期化
    *
    * @return void
    */
    public function resetModal()
    {
        $this->modals = [];
    }
 
}

 

トレイトの内容を、そのままクラスに置き換えました。このクラスにメッセージを格納することで一元管理をしていきましょう。

 

ヘルパー関数

さて、前項で説明したグローバル関数と、新しく作成したレスポンスクラスを使って一元管理をするとしましたが、実際にどのように紐付けていくかがネックです。

例えばポケモンクラス内でレスポンスクラスにアクセスするためには、メソッド内でグローバル関数の宣言が必要になります。

/**
* 正式名称を取得する
* @return string
*/
public function getName()
{
    global $global;
    return $this->name;
}

 

これを全メソッドに行うとなれば、明らかに非効率的です。なので、グローバル宣言をしなくても呼び出せるグローバル関数を経由することで、グローバル変数に用意されたレスポンスのインスタンスにアクセスし、メソッドを呼び出す方法を取ります。

これを、フレームワークなどで名称活用されている「ヘルパー関数」としましょう。

 

全クラス内から共通インスタンスへのアクセス

それでは、全クラス内からアクセスできるレスポンスインスタンスを作成しましょう。

レスポンス関係のヘルパー関数を格納するファイル(ResponseGlobal.php)を作成し、これをページの最初で読み込んでおきます。

require_once(__DIR__.'/App/Globals/ResponseGlobal.php');

 

それでは、ヘルパー関数の作成方法を見ていきましょう。以下、メッセージを取得するためのヘルパー関数です。

<?php
// レスポンス用グローバル関数
$root_path = __DIR__.'/../..';
// クラス読み込み
require_once($root_path.'/Classes/Response.php');
$global_responses = new Response;
 
/**
* メッセージの取得
* @return array
*/
function getMessages()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}

 

ポイントは、関数名とレスポンスのメソッド名を合わせているという点です。こうしておくことで、__FUNCTION__で現在の関数名が取得できるので、そのままグローバル変数のメソッド名として使用することができます。

もし他のインスタンスに対して用意する際に、メソッド名が重複する場合は、関数名を取得せず、メソッド指定で呼び出すようにしておきましょう。

 

次に、引数指定があるメッセージの格納用のヘルパー関数を見ていきましょう。

/**
* メッセージの格納
* @param string|array $msg
* @param mixed $param
* @return void
*/
function setMessage($msg, $param=null)
{
    global $global_responses;
    $name = __FUNCTION__;
    $global_responses->$name($msg, $param);
}

こちらは、引数をそのまま指定するだけでOKです。この要領で、レスポンス用のヘルパー関数を作成していきましょう。

 

レスポンス用ヘルパー関数
<?php
// レスポンス用グローバル関数
$root_path = __DIR__.'/../..';
// クラス読み込み
require_once($root_path.'/Classes/Response.php');
$global_responses = new Response;
 
/**
* メッセージIDの発行
* @return string
*/
function issueMsgId()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}
 
/**
* 全リセット
* @return void
*/
function resetResponsesAll()
{
    global $global_responses;
    $name = __FUNCTION__;
    $global_responses->$name();
}
 
/**==================================================================
* メッセージ関係の処理
==================================================================**/
/**
* メッセージの取得
* @return array
*/
function getMessages()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}
 
/**
* メッセージの格納
* @param string|array $msg
* @param mixed $param
* @return void
*/
function setMessage($msg, $param=null)
{
    global $global_responses;
    $name = __FUNCTION__;
    $global_responses->$name($msg, $param);
}
 
/**
* アニメーション用の自動メッセージの格納
*
* @param mixed $param
* @return void
*/
function setAutoMessage($param)
{
    global $global_responses;
    $name = __FUNCTION__;
    $global_responses->$name($param);
}
 
/**
* 空メッセージの格納
*
* @param string $param
* @return void
*/
function setEmptyMessage(string $param='')
{
    global $global_responses;
    $name = __FUNCTION__;
    $global_responses->$name($param);
}
 
/**
* メッセージの初期化
* @return void
*/
function resetMessage()
{
    global $global_responses;
    $name = __FUNCTION__;
    $global_responses->$name();
}
 
/**
* メッセージの最初のキーを取得
*
* @return mixed
*/
function getMessageFirstKey()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}
 
/**
* メッセージの最後のキーを取得
*
* @return mixed
*/
function getMessageLastKey()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}
 
/**==================================================================
* レスポンス関係の処理
==================================================================**/
/**
* 指定したレスポンステータの取得
*
* @param string|integer
* @return mixed
*/
function getResponse($param)
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name($param);
}
 
/**
* レスポンステータの全取得
*
* @return array
*/
function getResponses()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}
 
/**
* レスポンステータの格納
*
* @param mixed $response
* @param mixed $key
* @return array
*/
function setResponse($response, $key=null)
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name($response, $key);
}
 
/**
* レスポンステータの初期化
*
* @return void
*/
function resetResponse()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}
 
/**==================================================================
* モーダル関係の処理
==================================================================**/
/**
* モーダルテータの取得
*
* @return array
*/
function getModals()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}
 
/**
* モーダル用テータの格納
*
* @param array $param
* @param boolean $merge
* @return array
*/
function setModal(array $param, bool $merge=false)
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name($param, $merge);
}
 
/**
* モーダル情報の初期化
*
* @return void
*/
function resetModal()
{
    global $global_responses;
    $name = __FUNCTION__;
    return $global_responses->$name();
}

 

一元化したことにより、セッションを活用したメッセージIDの重複チェックは不要かなと思っています。現在は支障が無いので、合間を見て修正をかけていきます。

また、現段階では可変長引数への対応ができないのと、プロパティへのアクセスができないため、exportPropertyメソッドは不要になりました。

 

あとは、全コードのメッセージやレスポンスの格納方法を変更するだけです。

例として、レベル技習得確認メソッド(checkeLevelMove)の記述を見てみましょう。

/**
* 現在のレベルで覚えられる技があるか確認する処理
*
* @return void
*/
protected function checkLevelMove()
{
    // レベルアップして覚えられる技があれば習得する
    $level_move_keys = array_keys(
        array_column($this->level_move, 0),
        $this->level
    );
    foreach($level_move_keys as $key){
        $move_class = $this->level_move[$key][1];
        // 覚えようとしている技(クラス)が存在かつ重複していないか
        if(!in_array($move_class, array_column($this->move, 'class'), true)){
            // インスタンス化
            $move = new $move_class;
            if(count($this->move) < 4){
                /**
                * 技が4つ未満なら即習得
                */
                // 技クラスをセット
                $this->setMove($move);
                setMessage($move->getName().'を覚えた!');
            }else{
                /**
                * 技選択用モーダルの返却
                */
                // メッセージIDを生成
                $msg_id = issueMsgId();
                // レベルアップメッセージ
                setMessage($this->getNickName().'は'.$move->getName().'を覚えたい');
                setMessage('しかし技を4つ覚えるので精一杯だ');
                setMessage($move->getName().'の代わりに他の技を忘れさせますか?', $msg_id);
                // レスポンスデータをセット
                setResponse([
                    'toggle' => 'modal',
                    'target' => '#'.$msg_id.'-modal',
                    'move' => $move_class
                ], $msg_id);
                // モーダル用のレスポンスをセット
                setModal([
                    'id' => $msg_id,
                    'modal' => 'selectmove',
                    'new_move' => $move
                ]);
                // 諦めメッセージを事前に用意しておく
                setMessage($this->getNickName().'は'.$move->getName().'を覚えるのを諦めた');
            }
        }
    }
}

 

大分スマートになりました。また、今まで引き継ぎ処理としていたメッセージを取得してコントローラーのメッセージに格納、その後取得先のメッセージをリフレッシュするという処理をなくすことができました。

  

まとめ

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

今回のPHPポケモンでは内部の修正として、グローバル・ヘルパー関数を活用した「レスポンスの一元化」の方法をご紹介しました。

この変更を本番環境に反映させる際には、再度セーブデータの全リセットを行う予定です。ご了承ください。

また、この変更に合わせて状態異常の演出に取り欠かれるので、こちらは近日中に実装します。

 

現在プログラミング学習に取り組んでいる方、興味を持たれている方は、ぜひ参考にしてみてくださいね。

 

注目の記事

アクセス層とは – 物理的な信号の伝送【第4回 ド素人のためのネットワーク講座】
ネットワーク
TCP/IP,Wi-Fi,アクセス層,無線LAN
アクセス層とは – 物理的な信号の伝送【第4回 ド素人のためのネットワーク講座】

  第4回のド素人のためのネットワーク講座は アクセス層の物理的な役割について です。   実際にデータを送る際にはどのような信号が送られて、どういったことに影響を受けているのかを解説していきます。     信号を伝達する   TCP/IPモデルの第一層(レイヤー1)のアクセス層が担っている役割の...

ネコにこばん編 PHPポケモン73
プログラミング
PHP,PHPポケモン,ポケモン
ネコにこばん編 PHPポケモン73

ネコにこばんとは 初代ポケモンでは、基本的にトレーナーとのバトルでしかお金を増やすことができず、もし手持ち金が0円の状態で金が必要なイベントが発生すると詰んでしまうという隠された落とし穴がありました。 ですが、初代でも唯一トレーナー意外からお金を得る方法があります。それが「ネコにこばん」という...

YouTuber・ブロガー必見!知る人ぞ知るサムネイルの重要性とは
デザイン
Facebook,Instagram,Twitter,YouTuber,サムネイル,ブロガー
YouTuber・ブロガー必見!知る人ぞ知るサムネイルの重要性とは

  サムネイルって本当に重要? ブログの場合はフリー画像でもいいんじゃない?   そう考えている人はいませんか? 残念ですが、それは大きな間違いです。サムネイルを作り込むことは非常に重要であり、集客ポイントを拡大させるのはもちろん、ブランディングにもつながるのです。   今回は「知る人ぞ...

config実装編(ドット記法・多次元配列) PHPポケモン 71
プログラミング
PHP,PHPポケモン,ポケモン
config実装編(ドット記法・多次元配列) PHPポケモン 71

configファイルの作成 プログラミングでは設定値というものを使うことが良くあります。量が多い場合はデータベースへ格納して管理する場合も多いですが、わざわざテーブルを用意してまで格納するほどのものでなければ、ファイルに配列として定義してアクセスできる方が便利です。フレームワークではこれらをconfigフ...

パーティー実装編 戦闘に参加するポケモン PHPポケモン64
プログラミング
PHP,PHPポケモン,ポケモン
パーティー実装編 戦闘に参加するポケモン PHPポケモン64

先頭のポケモンを選出 前回パーティーのプロパティを準備して、複数(6匹)のポケモンを持ち歩けるようにすることを想定しました。 今回は、そこからバトル画面への連動をさせる部分までを作り込んでいきましょう。   複数のポケモンを所有している場合、戦闘が始まって繰り出されるのは「ひんし状態を除く一番上...

なぜ、お金を配るの?悪質メール・SNSを利用した詐欺的手法への対処法とは
ネットワーク
amazon,SNS,Twitter,お金配り,楽天,迷惑メール
なぜ、お金を配るの?悪質メール・SNSを利用した詐欺的手法への対処法とは

定期的に書きたくなるコラムのコーナー! 今回は、迷惑メールやSNSのDMを活用した悪質な勧誘、巷で流行っているお金配りを隠れ蓑のした巧妙な詐欺的手法などをいくつかご紹介、その対策・リクス回避の方法をまとめました。   まず結論からお伝えすると 「怪しいと思うなら手を出すな」 です。その詳細を知りたい...

「数字を上げる」必勝マニュアル 〜再生回数・フォロワー・PV数〜
マーケティング
YouTuber,ブロガー,必勝マニュアル,自己啓発
「数字を上げる」必勝マニュアル 〜再生回数・フォロワー・PV数〜

  「継続は力なり」   色んな場面で言われます。何事も地道な努力が大事です。 しかし、地道な努力というのは成果が見えづらく、反応が得にくいことも確かです。   運良く勢いに乗れて、常に努力のし易い環境にいることで伸びていく人の確かにいます。 しかし、ほとんどの人がそうはいきません。...

EC-CUBE4内にWordPressを設置(共存)する方法
SEO対策,プログラミング
EC-CUBE4,PHP,Symfony,Twig,WordPress
EC-CUBE4内にWordPressを設置(共存)する方法

今回使用したバージョン EC-CUBE4.0.5 WordPress5.6 ※EC-CUBE4、WordPressのカスタマイズは自己責任でお願いします。また、現在稼働中のサイトで試す際には、必ずバックアップを取ってから行なうようにしてください。   EC-CUBE4とは ネットショップを作るとなれば、様々なサービスが出回っ...

カテゴリ

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