プログラミング

グローバル&ヘルパー関数編 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ポケモンでは内部の修正として、グローバル・ヘルパー関数を活用した「レスポンスの一元化」の方法をご紹介しました。

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

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

 

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

 

注目の記事

フレンドリィショップ編 アイテムの販売 PHPポケモン 76
プログラミング
PHP,PHPポケモン,ポケモン
フレンドリィショップ編 アイテムの販売 PHPポケモン 76

リュックの作成 前回はフレンドリィショップへ商品を並べ、計算機を作成するところまで作成しました。ですが、商品が購入できたとしても、それを保管しておくためのスペースがなければ意味がありません。 なので、プレイヤー情報に対してアイテムを格納できるように機能拡張をしましょう。   プレイヤークラス(/C...

PHPポケモン「バトルシステム実装編〜補正値計算・乱数・急所〜」21
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「バトルシステム実装編〜補正値計算・乱数・急所〜」21

バトルシステムの実装  今回は「急所」と「乱数」と「タイプ一致」の判定と補正を実装していきます。 ちなみにですが、ポケモンwikiを熟読したところ、補正値の計算にも順番があり、計算後に小数点の切り捨てや五捨五超入をするなど、そこそこ複雑な計算順序がありましたが、今回はそこまで精密に再現せず、補正値(...

戦闘不能による交代編 PHPポケモン84
プログラミング
PHP,PHPポケモン,ポケモン
戦闘不能による交代編 PHPポケモン84

戦闘不能による交代 ポケモンが戦闘不能になった際、もし手持ちに戦える状態のポケモンが残っていれば「交代」か「逃げる」の2択になります。今までは手持ちポケモンが1匹のみで判定を行っていたので、今回は交代の選択肢も含めて勝負の判定の見直しをしていきます。   パーティーを含めた勝負判定 味方または...

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

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

パーティーの並び替え編 PHPポケモン 82
プログラミング
PHP,PHPポケモン,ポケモン
パーティーの並び替え編 PHPポケモン 82

パーティーの並び替え ポケモンをバトルに選出する際に欠かせないのが「パーティーの並び替え」です。パーティーの先頭(ひんし状態でない)がポケモンでは自動的に選択されるため、戦闘前に並び替えをしておく必要があります。 ゲーム上では簡単に見える処理ですが、これがPHPで行うとなれば少し厄介な問題が出てき...

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

進化や技習得、HPバーや経験値バーの演出ができているのに、なぜ状態異常の演出はされていないの?   そう感じている方が少なからずいるはずです。 現段階では、状態異常になっても次の画面に移管しなければ表示されません。これは、PHP側で内部処理は行われているが、メッセージに合わせた動的な変更がされていな...

PHPポケモン「オートローダー編」16
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「オートローダー編」16

  今までは技やタイプを一括requireという荒業で対応していましたが、フシギダネ系列の技を実装した際に「こんなん全部読み込んでられるか!」と流石になったので、簡易ながらオートローダーを実装していきます。 そして、実装したらしたで色々と問題も浮かび上がってきたので、このあたりは回を進めて行きなが...

アーカイブのディスクリプションを管理画面で設定する方法【SEOに強いWordPressブログ・サイト作り】
プログラミング
PHP,SEO,WordPress
アーカイブのディスクリプションを管理画面で設定する方法【SEOに強いWordPressブログ・サイト作り】

  WordPressで作ったサイトやブログはSEO対策がしやすいという利点があり、より検索に強いサイトへ仕上げることができます。 ですが、SEO対策に特化しているテーマでもアーカイブページのディスクリプション設定ができないものは多く、別で設定する必要があるものがほとんどです。   今回は、より検索で強く...

カテゴリ

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