プログラミング

グローバル&ヘルパー関数編 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ポケモン66
プログラミング
PHP,PHPポケモン,ポケモン
ビジュアル作り込み編(序) PHPポケモン66

ビジュアルの作り込み 最近は内部の作り込みが多かったので、今回のPHPポケモンでは見た目を少しだけ作り込んでいきます。とはいっても、機能自体がそこまで揃っていないため、あくまで仮の見た目となります。 ある程度見た目が整っていると、プレイする側のモチベーションや楽しみも増えると思ったので、こちらは並...

XserverにSequel ProでSSH接続する方法を4ステップでわかりやすく解説
ネットワーク
phpMyAdmin,Sequel Pro,SSH,Xserver,データベース,公開鍵,秘密鍵
XserverにSequel ProでSSH接続する方法を4ステップでわかりやすく解説

  AWSなどが注目される中、Xserver(エックスサーバー)は操作やセットアップが簡単で、ポートフォリオや業務、個人ブログ(WordPess)で使用している方に需要が高いサービスです。 そしてMacのPCを使っている方はデータベースの管理ツールとして、無料で使えるSequel Proが人気があり、多くのユーザーが使用し...

動画編集で知っておくべき基本的な3工程
動画編集
Adobe,AfterEffects,Illustrator,Photoshop,PremierePro
動画編集で知っておくべき基本的な3工程

  YouTubeに動画を投稿したいけど、動画の基本的な作成手順がわからない・・・   動画作成をするためのソフトは色々ありますが、有料なものであればやはりAdobe製品に軍配が上がります。 しかし準備したは良いものの、いろんなソフトが合ってどれを使えばよいか分からないという悩みを抱えている方は非常...

OSI参照モデルとTCP/IP 〜ネットワークモデルとは〜【第3回 ド素人のためのネットワーク講座】
ネットワーク
OSI参照モデル,TCP/IP,ネットワークモデル,プロトコル
OSI参照モデルとTCP/IP 〜ネットワークモデルとは〜【第3回 ド素人のためのネットワーク講座】

  ド素人のためのネットワーク講座! 栄えある第3回は「ネットワークモデル」についてです。   横文字や英字が多くなってきたり、歴史的経緯が関係してきたりとややこしくなってくる部分ですが、ネットワークを理解するためには押さえておきたいポイントです。   プログラミングやシステムエンジニアとし...

データ軽量化編 β版へ向けて  PHPポケモン 90
プログラミング
PHP,PHPポケモン,ポケモン
データ軽量化編 β版へ向けて PHPポケモン 90

β版の実装に向けて 大型アップデートにより、ある程度機能改善や実装箇所も増えてきましたが、それと同時に次の段階への移行が本格的に見えてきました。それがβ版です。   PHPポケモンは2020年12月現在α版となっており、完全な試作段階のWEBアプリケーションです。セーブ機能はなく、セッションの有効期...

レベニューシェアとは?利益報酬・共同事業に潜む罠
フリーランス
レベニューシェアとは?利益報酬・共同事業に潜む罠

  レベニューシェアという言葉を聞いたことがありますか?   ビジネスの世界にいる人なら、意味は知らなくてもやったことがある方が意外と多いはずです。特にフリーランスの人や、プログラミングやデザインといったスキルを持っている人はレベニューシェアでは重宝されるため多い傾向があります。ここ最近...

非公開ディレクトリ画像表示編 PHPポケモン 91
プログラミング
PHP,PHPポケモン,ポケモン
非公開ディレクトリ画像表示編 PHPポケモン 91

非公開ディレクトリの画像を表示する 今回は、β版に向けての取り組みの1つとして、表示させる画像のアクセス先を非公開ディレクトリに変更します。 現在は公開ディレクトリ(Public)内のAssetsフォルダ内に配置していますが、これをルート直下においているStorageに移動させるのが目的となります。   gifのbas...

カテゴリ

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