PHPで電卓アプリの作成

PHPの勉強のためにPHPとHTMLで簡単な電卓アプリを作成してみました。
色々と不備があるかもしれませんがそこは何卒ご容赦ください。

<h1>目次</h1>

[1. アプリの作成](#アプリの作成)
・ [作成したアプリ](#作成したアプリ)
・ [完成イメージ](#完成イメージ)
・[画面側のコード](#画面側のコード)
・[画面側コード説明](#画面側コード説明)
　- [ディスプレイ表示](#ディスプレイ表示)
　- [hidden](#hidden)
　- [table](#table)
・ [処理プログラムのコード](#処理プログラムのコード)
・[処理プログラムの説明](#処理プログラムの説明)
　- [変数の定義](#変数の定義)
　- [関数の定義](#関数の定義)
　- [数字ボタンが押された時](#数字ボタンが押された時)
　- [四則演算以外の記号が押された時](#四則演算以外の記号が押された時)
　- [数字ボタンを押下後に記号ボタンかイコールを押下](#数字ボタンを押下後に記号ボタンかイコールを押下)
<h2>
<span id="アプリの作成" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>アプリの作成</h2>
<h3>
<span id="作成したアプリ" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>
作成したアプリ</h3>
<img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/95a4b1f75a1d2c0b3c7661ba94ccf213.png" alt="" width="544" height="550" class="aligncenter wp-image-1851 size-full" />

操作デモ映像
<iframe width="389" height="692" src="https://www.youtube.com/embed/fmaAuoTBYRA" title="【デモ映像】PHPで電卓アプリの作成" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


<h3><span id="完成イメージ" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>完成イメージ</h3>
「<strong>簡易電卓アプリ</strong>」の作成に伴いまず初めにiPhoneの電卓をイメージしてみました。

<img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/IMG_7342-473x1024.png" alt="" width="473" height="1024" class="aligncenter wp-image-1848 size-large" />

横画面表示ではより多機能な電卓となります。

<img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/IMG_7343-1024x473.png" alt="" width="1024" height="473" class="aligncenter wp-image-1850 size-large" />

今回目指す電卓ではデザインは無視して、単純に電卓として機能するものを完成イメージとしました。

<strong>【基本機能】</strong>
<strong>・数字：0〜9</strong>
<strong>・記号：四則演算記号、符号の切り替え、百分率、オールクリア、小数点</strong>
<strong>・ディスプレイ表示</strong>

<strong>【追加機能】</strong>
<strong>・指数計算</strong>
<strong>・ネイピア数(e)</strong>
<strong>・クリア</strong>

ざっくりこんな感じで作成イメージを考えました。追加機能に関しては基本機能が完成した後から追加した機能になります。
<h3><span id="画面側のコード" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>画面側のコード</h3>
まずは見た目の作成に取り掛かりました。といっても見た目は簡易的なものなので複雑なコードはありません。全体を表示します。


```PHP:画面側全体
<?php require_once("CalculatorApp.php")?>

<!DOCTYPE html>
<html>
    <head>
        <title>電卓アプリケーション</title>
    </head>
    <body>
        <h2>電卓アプリケーション</h2>
            <p><?php if(empty($displayNum)){echo 0;}else{echo $displayNum;} ?></p>
        <form action="?" method="post">
            <input type="hidden" name="displayNum" value="<?php echo $displayNum;?>"/>
            <input type="hidden" name="pre_button" value="<?php echo $pre_button;?>"/>
            <input type="hidden" name="ope" value="<?php echo $ope;?>"/>
            <input type="hidden" name="pre_num" value="<?php echo $pre_num;?>"/>
            <input type="hidden" name="input_num" value="<?php echo $input_num;?>"/>


            <table>
                <tr align="center">
                    <td><button type="submit" name="button" value="e^x">e^x</button></td>
                    <td><button type="submit" name="button" value="x^y">x^y</button></td>
                    <td><button type="submit" name="button" value="10^x">10^x</button></td>
                    <td><button type="submit" name="button" value="x^2">x^2</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="AC">AC</button></td>
                    <td><button type="submit" name="button" value="C">C</button></td>
                    <td><button type="submit" name="button" value="%">%</button></td>
                    <td><button type="submit" name="button" value="÷">÷</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="7">7</button></td>
                    <td><button type="submit" name="button" value="8">8</button></td>
                    <td><button type="submit" name="button" value="9">9</button></td>
                    <td><button type="submit" name="button" value="×">×</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="4">4</button></td>
                    <td><button type="submit" name="button" value="5">5</button></td>
                    <td><button type="submit" name="button" value="6">6</button></td>
                    <td><button type="submit" name="button" value="-">-</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="1">1</button></td>
                    <td><button type="submit" name="button" value="2">2</button></td>
                    <td><button type="submit" name="button" value="3">3</button></td>
                    <td><button type="submit" name="button" value="+">+</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="0">0</button></td>
                    <td><button type="submit" name="button" value="+/-">+/-</button></td>
                    <td><button type="submit" name="button" value="e">e</button></td>
                    <td><button type="submit" name="button" value="=">=</button></td>
                </tr>
            </table>
        </form>
    </body>
</html>
```

<h3><span id="画面側コード説明" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>画面側コード説明</h3>
<h4><span id="・ディプレイ表示" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>・ディスプレイ表示</h4>


```PHP
<p><?php if(empty($displayNum)){echo 0;}else{echo $displayNum;} ?></p>
```

ディスプレイに表示するための変数「<strong>$displayNum</strong>」が空、つまりボタンを押してないかクリアした状態なら0を表示しておき、それ以外は変数に格納された値を表示します。
<h4><span id="・hidden" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>・hidden</h4>

```HTML
<input type="hidden" name="displayNum" value="<?php echo $displayNum;?>"/>
<input type="hidden" name="pre_button" value="<?php echo $pre_button;?>"/>
<input type="hidden" name="ope" value="<?php echo $ope;?>"/>
<input type="hidden" name="pre_num" value="<?php echo $pre_num;?>"/>
<input type="hidden" name="input_num" value="<?php echo $input_num;?>"/>
```


各変数の値を表示せず保持させます。
<h4><span id="・table" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>・table</h4>


```HTML
<table>
                <tr align="center">
                    <td><button type="submit" name="button" value="e^x">e^x</button></td>
                    <td><button type="submit" name="button" value="x^y">x^y</button></td>
                    <td><button type="submit" name="button" value="10^x">10^x</button></td>
                    <td><button type="submit" name="button" value="x^2">x^2</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="AC">AC</button></td>
                    <td><button type="submit" name="button" value="C">C</button></td>
                    <td><button type="submit" name="button" value="%">%</button></td>
                    <td><button type="submit" name="button" value="÷">÷</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="7">7</button></td>
                    <td><button type="submit" name="button" value="8">8</button></td>
                    <td><button type="submit" name="button" value="9">9</button></td>
                    <td><button type="submit" name="button" value="×">×</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="4">4</button></td>
                    <td><button type="submit" name="button" value="5">5</button></td>
                    <td><button type="submit" name="button" value="6">6</button></td>
                    <td><button type="submit" name="button" value="-">-</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="1">1</button></td>
                    <td><button type="submit" name="button" value="2">2</button></td>
                    <td><button type="submit" name="button" value="3">3</button></td>
                    <td><button type="submit" name="button" value="+">+</button></td>
                </tr>
                <tr align="center">
                    <td><button type="submit" name="button" value="0">0</button></td>
                    <td><button type="submit" name="button" value="+/-">+/-</button></td>
                    <td><button type="submit" name="button" value="e">e</button></td>
                    <td><button type="submit" name="button" value="=">=</button></td>
                </tr>
            </table>
```

tableタグを利用してボタンを等間隔に配置しています。

<img src="https://hiro-hobbyblog.com/wp-content/uploads/2022/10/26731649a7db8a52be213c782b631de8.png" alt="" width="697" height="492" class="aligncenter wp-image-1856 size-full" />

<a href="https://saruwakakun.com/html-css/basic/table">画像の引用元：サルワカ</a>
<h3>処理プログラムのコード</h3>

```PHP:処理側全体
<?php
//------------------------変数の定義-------------------------

$displayNum = $_POST['displayNum'];
$pre_num = $_POST['pre_num'];
$ope = $_POST['ope']; 
$pre_button = $_POST['pre_button']; 
$button = $_POST['button']; 
$input_num = $_POST['input_num']; 

//----------------------------------------------------------

//------------------------処理の内容--------------------------

//＜＜＜＜＜＜＜＜＜＜＜＜数字ボタンが押された場合＞＞＞＞＞＞＞＞＞＞＞＞＞
if(isNumBtn($button)||empty($button)){
    //次に記号を押した場合
    if(isSymBtn($pre_button)){
        $pre_num = $displayNum;
        $displayNum = $button; //次に押した数字が表示される
    }else{ //連続で数字が押された場合
            
            //01や02と表示されないようにする
            if(($displayNum == '0') && (isNumBtn($button) != '0')){ 
                $displayNum = '';
            }

            $displayNum = $displayNum.$button;
    }


}else{

//＜＜＜＜＜＜＜＜＜＜＜＜記号ボタンが押された場合＞＞＞＞＞＞＞＞＞＞＞＞＞＞
    switch($button){
        case 'AC': //オールクリア
            $displayNum = '';
            $pre_num = '';
            $input_num = '';
            break;

        case '+/-': //符号反転
            $displayNum = -$displayNum;
            break;

        case '%': //百分率
            $displayNum = $displayNum / 100;
            break;

        case 'x^2': //二乗
            $displayNum *= $displayNum;
            break;

        case 'e': //ネイピア数
            $displayNum = $displayNum * 2.718281828459045;
            break;    

        case 'e^x': //ネイピア数の累乗
            $displayNum = 2.718281828459045 ** $displayNum;
            break;

        case '10^x': //10の累乗
            $displayNum = 10 ** $displayNum;
            break;
            default: //次の処理へ

            //すでに数字ボタンが押されており、次に押すボタンが記号ボタンまたは「=」の場合
        if(!empty($pre_num)&&(preg_match('/=/', $button)||(isNumBtn($pre_button)&&isSymBtn($button)))){
            switch($ope){
                case '+':
                    $displayNum = $pre_num + $displayNum;
                    break;
                case '-':
                    $displayNum = $pre_num - $displayNum;
                    break;
                case '×':
                    $displayNum = $pre_num * $displayNum;
                    break;
                case '÷':
                    $displayNum = $pre_num / $displayNum;
                    break;

                case 'x^y':
                    $displayNum = $pre_num ** $displayNum;
                    break;
                    default:
                    break;
            }

            //現在入力中の値をクリア
            if($button == "C"){
                $displayNum = $pre_num;
                $ope = '';
                $pre_button = $pre_num;
                break;
            }
        }
        //「=」を押さない場合
        if ($button != '＝'){
            $ope = $button;  
        }      
    break;
    }
}
//押したボタンの数字を表示
$pre_button = $button;
//----------------------------------------------------------

//------------------------関数の定義--------------------------

//記号ボタンの判別に関する関数
function isSymBtn($btn){
    if($btn=='+'||$btn=='-'||$btn=='×'||$btn=='÷'||$btn=='AC'||$btn=='C'||$btn=='x^2'||$btn=='%'||$btn=='+/-'||$btn=='e'||$btn=='e^x'||$btn=='x^y'||$btn=='10^x'){
        return true;
    }else{
        return false;
    }
}

//数字ボタンの判別に関する関数
function isNumBtn($btn){
    if($btn=='0'||$btn=='1'||$btn=='2'||$btn=='3'||$btn=='4'||$btn=='5'||$btn=='6'||$btn=='7'||$btn=='8'||$btn=='9'){
        return true;
    }else{
        return false;
    }
}

//----------------------------------------------------------
?>


```
<h3><span id="処理プログラムの説明" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>処理プログラムの説明</h3>
<h4><span id="・変数の定義" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>・変数の定義</h4>

```PHP:変数の定義
$displayNum = $_POST['displayNum'];
$pre_num = $_POST['pre_num'];
$ope = $_POST['ope']; 
$pre_button = $_POST['pre_button']; 
$button = $_POST['button']; 
$input_num = $_POST['input_num']; 
```

画面側で保持している値を「<strong>$_POST</strong>」で受け取り、各変数に格納しています。
<h4><span id="・関数の定義" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>・関数の定義</h4>
順番は前後しますがこちらを先に触れておきます。

```PHP:関数の定義
//記号ボタンの判別に関する関数
function isSymBtn($btn){
    if($btn=='+'||$btn=='-'||$btn=='×'||$btn=='÷'||$btn=='AC'||$btn=='C'||$btn=='x^2'||$btn=='%'||$btn=='+/-'||$btn=='e'||$btn=='e^x'||$btn=='x^y'||$btn=='10^x'){
        return true;
    }else{
        return false;
    }
}

//数字ボタンの判別に関する関数
function isNumBtn($btn){
    if($btn=='1'||$btn=='2'||$btn=='3'||$btn=='4'||$btn=='5'||$btn=='6'||$btn=='7'||$btn=='8'||$btn=='9'){
        return true;
    }else{
        return false;
    }
}
```

「関数<strong>isSymBtn()</strong>」では記号ボタンが押されたときにtrueを返します。

「関数<strong>isNumBtn()</strong>」では数字ボタンが押されたときにtrueを返します。
<h4><span id="数字ボタンが押された時" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>数字ボタンが押された時</h4>

```PHP
//＜＜＜＜＜＜＜＜＜＜＜＜数字ボタンが押された場合＞＞＞＞＞＞＞＞＞＞＞＞＞
if(isNumBtn($button)||empty($button)){
    //次に記号を押した場合
    if(isSymBtn($pre_button)){
        $pre_num = $displayNum;
        $displayNum = $button; //次に押した数字が表示される
    }else{ //連続で数字が押された場合
            
            //01や02と表示されないようにする
            if(($displayNum == '0') &amp;&amp; (isNumBtn($button) != '0')){ 
                $displayNum = '';
            }

            $displayNum = $displayNum.$button;
    }
```

数字ボタンが押された後どのような動作を行うかをif文を用いて処理します。

数字ボタンを押した後に記号ボタンを押した場合、ディスプレイに表示されていた数字が変数「<strong>$pre_num</strong>」に格納され、次に押したボタンの数字がでディスプレイに表示されます。

例えば「1+2」の場合で考えると、「+」を押した時は画面には「1」が表示されたままですが、「2」を押した時「2」がディスプレイに表示されています。この時画面側では<strong>hidden属性</strong>により「<strong>$pre_num</strong>」には「1」が保持された状態になっています。

次にelseによって「<strong>連続で数字が押された場合</strong>」の処理を行います。この時、「01」や「00」は電卓における表示では不適切なのでフィルターをかけていきます。

処理は単純で、ディスプレイに「0」が表示されている時に「数字ボタン」が押されると、ディスプレイに表示されていた「0」に空文字が代入され、結果的に目的の押したボタンを表示する処理ができます。
<h4>・四則演算以外の記号が押された時</h4>

```PHP
//＜＜＜＜＜＜＜＜＜＜＜＜記号ボタンが押された場合＞＞＞＞＞＞＞＞＞＞＞＞＞＞
    switch($button){
        case 'AC': //オールクリア
            $displayNum = '';
            $pre_num = '';
            $input_num = '';
            break;

        case '+/-': //符号反転
            $displayNum = -$displayNum;
            break;

        case '%': //百分率
            $displayNum = $displayNum / 100;
            break;

        case 'x^2': //二乗
            $displayNum *= $displayNum;
            break;

        case 'e': //ネイピア数
            $displayNum = $displayNum * 2.718281828459045;
            break;    

        case 'e^x': //ネイピア数の累乗
            $displayNum = 2.718281828459045 ** $displayNum;
            break;

        case '10^x': //10の累乗
            $displayNum = 10 ** $displayNum;
            break;
            default: //次の処理へ
```

後述しますが、「<strong>オールクリア</strong>」と「<strong>クリア</strong>」の区別は明確に分けておく必要があります。「オールクリア」では名前の通り、<strong>画面が保持している情報の一切を初期値に戻します</strong>。つまり各変数に格納されている値が空文字である必要があります。

その他の処理は説明がなくても見た目通りとなるのでここでは割愛します。
<h4><span id="数字ボタンを押下後に記号ボタンかイコールを押下" class="fragment"></span><a href="#%E8%A6%8B%E5%87%BA%E3%81%97-2"><i class="fa fa-link"></i></a>・数字ボタンを押下後に記号ボタンかイコールを押下</h4>

```PHP
//すでに数字ボタンが押されており、次に押すボタンが記号ボタンまたは「=」の場合
        if(!empty($pre_num)&amp;&amp;(preg_match('/=/', $button)||(isNumBtn($pre_button)&amp;&amp;isSymBtn($button)))){
            switch($ope){
                case '+':
                    $displayNum = $pre_num + $displayNum;
                    break;
                case '-':
                    $displayNum = $pre_num - $displayNum;
                    break;
                case '×':
                    $displayNum = $pre_num * $displayNum;
                    break;
                case '÷':
                    $displayNum = $pre_num / $displayNum;
                    break;

                case 'x^y':
                    $displayNum = $pre_num ** $displayNum;
                    break;
                    default:
                    break;
            }

            //現在入力中の値をクリア
            if($button == "C"){
                $displayNum = $pre_num;
                $ope = '';
                $pre_button = $pre_num;
                break;
            }
        }
        //「=」を押さない場合
        if ($button != '＝'){
            $ope = $button;  
        }      
    break;
    }
```

ここでは最初に押されたボタンの数字が格納されている「<strong>$pre_num</strong>」と後から押されたボタンの数字が格納されている「<strong>$displayNum</strong>」を使って計算をする処理です。

また、「<strong>クリア（C）</strong>」は今表示されているボタンの数字を削除して、新しく数字ボタンを押して計算し直すという処理にしたいので、「1+2」という計算の場合,

<strong>$pre_num = 1</strong>
<strong>$displayNum = 2</strong>

がそれぞれ格納されているので、ディスプレイに表示される値を前に押した数字「1」に戻して、四則演算の記号ボタンを押す前の処理に戻します。
<h2>最後に</h2>
単純なプログラムでも0からコーディングしようとすると結構苦労しました。改めて世の中に溢れているアプリに対する畏敬の念が積もるばかりです。

そして今回簡易アプリを作成する中で非常に重要に感じたのは「<strong>デバッグ</strong>」と「<strong>イメージ</strong>」でした。デバッグに関しては言わずもがな頻繁に使うので私のような初心者の方は絶対に初めから活用していくべきです。

そして「イメージ」ですが、私のような学習を主として作成するようなアプリは全て既存アプリのマネタイズになると思うので、今回であればiPhoneの電卓アプリの挙動を逐一確認しながらプログラムを書いていきました。

今後も個人学習としてアプリの作成を行っていきたいと思っていますので、その際はまた記事でアップしていこうと思います。