【PHP/HTML/CSS】計算機アプリの作成 #2 〜プログラミング初級編〜

動く計算機アプリ

前回の記事では「HTML」と「CSS」のみで計算機アプリの画面側の作成だけ行いました。

まだ記事を見ていない方はこちらからどうぞ!

前回の工程を踏まえて、今回は「動く計算機アプリ」を作成していきたいと思います!

今回は前回とは異なり「PHP」というバックエンド言語を使用して計算処理を行っていますので、前回よりも若干難易度が上がっていますが、処理自体はシンプルなものなので少しずつでも理解していきましょう。

目次

完成画面はこちら!

前回作成した画面のUIはそのままに、簡易的な計算機能を備えた「動く計算機アプリ」の完成画面です。

基本機能ながら、初心者にとっては意外と難しめに感じる部分もあり、学習材料としてはおすすめのアプリとなっています。

画面側を作成→裏側のロジックを構築」という一連の流れが体験できるので、ぜひ計算機アプリ作成にチャレンジしてみましょう!

実際のソースコードを確認してみよう!

今回は「PHP」を利用しているため、バックエンド言語の記述方法や特徴について焦点を当てながらソースコードを確認してみましょう!

HTML・CSS部分の説明については前回の記事を確認してみてください。

フォーム送信+PHPで計算処理を実装

HTML/CSSで作成した画面のボタンを押すとページが読み込まれ、値の授受が行われます。

ボタンを押すたびにページを再読み込み(POSTリクエスト)

HTMLの<form method="post">内にボタン(<button>)を配置し、押されたボタンの情報を$_POST経由でPHPが受け取ります。

PHPが受け取った値に応じて演算を実行

ページ上に見えている、

  • ディスプレイの値(表示されている数字)
  • 前に押した演算子
  • 前に入力した数字

などの状態は、フォームの<input type="hidden">で同時に送られます。

PHPでそれらの値を取り出してボタンに応じた処理(四則演算、符号反転、パーセント、リセットなど)を行い、新しい結果を計算していきます。

計算結果を再度HTMLに埋め込み、表示を行う

計算後のディスプレイ値を<div class="display">ここに結果</div>に表示してページを返すため、画面が更新されるたびに最新の計算結果が表示されるようになります。

では、さっそく実際のソースコードを確認してみましょう。

<?php
// -----------------------------------------------
// 1. 初期値の設定
// -----------------------------------------------
$display     = '0';   // 現在のディスプレイ値
$storedValue = '0';   // 演算前に記憶した値
$operator    = '';    // 現在の演算子 (+, -, ×, ÷ など)

// -----------------------------------------------
// 2. 隠しフィールドの値を取り出し、変数に代入
// -----------------------------------------------
if (isset($_POST['display'])) {
    $display = $_POST['display'];
}
if (isset($_POST['storedValue'])) {
    $storedValue = $_POST['storedValue'];
}
if (isset($_POST['operator'])) {
    $operator = $_POST['operator'];
}

// -----------------------------------------------
// 3. ボタン押下時の処理
// -----------------------------------------------
if (isset($_POST['button'])) {
    $button = $_POST['button'];

    switch ($button) {
        case 'AC':
            // 全リセット
            $display     = '0';
            $storedValue = '0';
            $operator    = '';
            break;

        case '±':
            // 符号反転
            if (is_numeric($display)) {
                $display = (string)((float)$display * -1);
            }
            break;

        case '%':
            // パーセント
            if (is_numeric($display)) {
                $display = (string)((float)$display / 100);
            }
            break;

        case '÷':
        case '×':
        case '−':
        case '+':
            // 演算子を入力 → 現在のdisplayを記憶し、演算子を保存
            $storedValue = $display;
            $operator    = $button;
            $display     = '0';  
            break;

        case '=':
            // = イコール → 記憶した値と現在のdisplayを演算
            if (is_numeric($storedValue) && is_numeric($display)) {
                $a = (float)$storedValue;
                $b = (float)$display;

                switch ($operator) {
                    case '+': $display = (string)($a + $b); break;
                    case '−': $display = (string)($a - $b); break;
                    case '×': $display = (string)($a * $b); break;
                    case '÷':
                        if ($b == 0) {
                            $display = 'Error'; // 0割り
                        } else {
                            $display = (string)($a / $b);
                        }
                        break;
                }
            }
            // 演算子はクリア
            $operator = '';
            break;

        default:
            // 数字・小数点入力の場合
            // displayが"0"または"Error"だった場合は置き換える
            if ($display === '0' || $display === 'Error') {
                $display = ($button === '.') ? '0.' : $button;
            } else {
                $display .= $button;
            }
            break;
    }
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>iPhone計算機UIデモ</title>
<link rel="stylesheet" href="calculatorStyles.css"/><!-- パスに注意 -->
</head>
<body>

<!--
  4. フォームを使うことで、ボタンクリック時にPHPへ値を送信
     計算用の隠しフィールドを使って状態を保持
-->
<form method="post" action="">
  <!-- 状態を保持するためのhiddenフィールド -->
  <input type="hidden" name="display" value="<?php echo htmlspecialchars($display); ?>">
  <input type="hidden" name="storedValue" value="<?php echo htmlspecialchars($storedValue); ?>">
  <input type="hidden" name="operator" value="<?php echo htmlspecialchars($operator); ?>">

  <div class="calculator">
    <!-- 現在のディスプレイ値を表示 -->
    <div class="display"><?php echo htmlspecialchars($display); ?></div>
    
    <div class="buttons">
      <div class="row">
        <button class="btn function" type="submit" name="button" value="AC">AC</button>
        <button class="btn function" type="submit" name="button" value="±">±</button>
        <button class="btn function" type="submit" name="button" value="%">%</button>
        <button class="btn operator" type="submit" name="button" value="÷">÷</button>
      </div>
      <div class="row">
        <button class="btn number" type="submit" name="button" value="7">7</button>
        <button class="btn number" type="submit" name="button" value="8">8</button>
        <button class="btn number" type="submit" name="button" value="9">9</button>
        <button class="btn operator" type="submit" name="button" value="×">×</button>
      </div>
      <div class="row">
        <button class="btn number" type="submit" name="button" value="4">4</button>
        <button class="btn number" type="submit" name="button" value="5">5</button>
        <button class="btn number" type="submit" name="button" value="6">6</button>
        <button class="btn operator" type="submit" name="button" value="−">−</button>
      </div>
      <div class="row">
        <button class="btn number" type="submit" name="button" value="1">1</button>
        <button class="btn number" type="submit" name="button" value="2">2</button>
        <button class="btn number" type="submit" name="button" value="3">3</button>
        <button class="btn operator" type="submit" name="button" value="+">+</button>
      </div>
      <div class="row">
        <!-- 0ボタンは2倍の横幅 -->
        <button class="btn zero number" type="submit" name="button" value="0">0</button>
        <button class="btn number" type="submit" name="button" value=".">.</button>
        <button class="btn operator" type="submit" name="button" value="=">=</button>
      </div>
    </div>
  </div>
</form>
</body>
</html>
html, body {
  margin: 0;
  padding: 0;
  background: #000;
  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, sans-serif;
}

.calculator {
  width: 100%;
  max-width: 400px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  height: 100vh;
  color: #fff;
}

.display {
  flex: 1;
  background: #000;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  font-size: 5rem;
  padding: 0 20px;
  box-sizing: border-box;
}

.buttons {
  background: #000;
  width: 100%;
}

.row {
  display: flex;
  width: 100%;
}

.btn {
  flex: 1;
  border: none;
  outline: none;
  font-size: 2rem;
  padding: 20px;
  text-align: center;
  box-sizing: border-box;
  color: #fff;
  border-top: 1px solid #333;
  border-right: 1px solid #333;
  background: #333;
  cursor: pointer;
}

.btn:active {
  filter: brightness(1.2);
}

.number {
  background: #505050;
}

.function {
  background: #a5a5a5;
  color: #000;
}

.operator {
  background: #f09a36;
}

.zero {
  flex: 2;
  text-align: left;
  padding-left: 45px;
}

ソースコードの解説

上記コードの処理の一部の簡単な流れは以下のようになっています。

  • ユーザーが「7」を押す → フォーム送信 → PHPはbutton=7と受け取り、今のディスプレイが「0」なら「7」に置き換え。
  • ユーザーが「+」を押す → フォーム送信 → 今のディスプレイの値「7」を記憶(storedValue)に保存、演算子を「+」に設定し、ディスプレイは「0」にリセット。
  • ユーザーが「3」を押す → ディスプレイは「3」に。
  • ユーザーが「=」を押す → フォーム送信 → storedValue(7)とディスプレイ(3)を演算子「+」で計算 → 結果「10」をディスプレイに表示。
  • ユーザーが「AC」を押す → すべてリセット → ディスプレイ「0」。

このように順を追ってみていくと、そんなに難しくないと思えるかもしれませんね。

①サーバーサイドでの計算

一般的に、計算機のように即時反応が必要な機能はJavaScript(ブラウザ側)で実装することが多いですが、ここでは「ページを再読み込みして結果を出す」方式をPHP(サーバー側)で行うようにしています。

各ボタンクリックごとにページが再読み込みされる(POSTリクエストが送信される)ので、計算結果をPHPが受け取り、処理したうえでHTMLを再生成・返却する仕組みとなっています。

②フォーム入力の扱い

  <!-- 状態を保持するためのhiddenフィールド -->
  <input type="hidden" name="display" value="<?php echo htmlspecialchars($display); ?>">
  <input type="hidden" name="storedValue" value="<?php echo htmlspecialchars($storedValue); ?>">
  <input type="hidden" name="operator" value="<?php echo htmlspecialchars($operator); ?>">

$_POSTで送られたデータを、$button$displayなどの変数に代入して処理しています。

隠しフィールド (<input type="hidden">) を使って、現在の表示中の数字や演算子といった状態をいったんHTMLに埋め込み、次のリクエストでも「前の状態」を受け取れるようにしています。

こうすることで、ページを切り替えても途中の計算状態が失われずに済みます(いわゆる「ステートフル(状態を持ち続ける)」な仕組みの実装方法のひとつ)。

isset() について

isset関数は、与えられた変数に値がセットされているか(nullでないか)を判定するための関数で、返り値は「true」か「false」になります。

if (isset($_POST['display'])) {
    $display = $_POST['display'];
}
if (isset($_POST['storedValue'])) {
    $storedValue = $_POST['storedValue'];
}
if (isset($_POST['operator'])) {
    $operator = $_POST['operator'];
}

ここでは、フォームの送信内容 ($_POST 配列) の中に 'display''storedValue''operator' という名前のデータが存在しているかどうかをチェックしています。

もし isset($_POST['display']) が true であれば、$_POST['display'] に何かしらの値が入っている(null でない)という意味であるため、$display 変数にその値を代入します。

まだフォームが送信されていなかったりその値が送られてこなかったりする場合は、isset() は false になり、代入は行われません。

よくある使われ方
・フォームデータが送信されているかチェックする
・セッション変数やクッキーがセットされているかチェックする
・変数が未定義でもエラーを回避したいとき

is_numeric() について

is_numeric() は、変数(または文字列)が数値として有効かどうか」を判定するための関数です。

数値・数値形式の文字列(”123″、”3.14″、”1e3″ など)であれば true を返し、それ以外は false を返します。

case '±':
    if (is_numeric($display)) {
        $display = (string)((float)$display * -1);
    }
    break;

case '%':
    if (is_numeric($display)) {
        $display = (string)((float)$display / 100);
    }
    break;

ここでは、± ボタンや % ボタンを押したときに、$display の値が数値として扱えるかどうかを is_numeric($display) でチェックしています。

数値として扱える場合は (float)$display として計算(符号反転や100分の1)を行い、計算後の値を $display に代入しています。

もし $display が "Error" など数値でない文字列になっている場合は is_numeric() が false を返すため計算処理はスキップされ、無理に計算してエラーを起こすようなことを防ぐことができます。

数値として有効な例
"123"(文字列だけど数字のみ)
"3.14"(小数点を含む文字列)
"1.2e3"(指数形式:1.2 × 103 = 1200)
45(そもそも数値型)

今回のコーディングのコツや特徴について

PHPとHTMLは相性の良い言語なので、互いに値を受け渡しやすい構造となっています。

その上で、PHPを利用したコーディングのコツや特徴について紹介していきます。

HTMLのボタン要素をフォーム送信に活用

      <div class="row">
        <button class="btn number" type="submit" name="button" value="7">7</button>
        <button class="btn number" type="submit" name="button" value="8">8</button>
        <button class="btn number" type="submit" name="button" value="9">9</button>
        <button class="btn operator" type="submit" name="button" value="×">×</button>
      </div>

<button type="submit" name="button" value="7">のように、各ボタンにパラメータを持たせることで「どのボタンを押したか」を簡単にPHPに伝えられます。

値を分かりやすく設定(数字なら数字、演算子なら演算子)しておくとPHP側の処理をシンプルに記述できるようになります。

PHPで状態を管理するときは隠しフィールドが便利

  <!-- 状態を保持するためのhiddenフィールド -->
  <input type="hidden" name="display" value="<?php echo htmlspecialchars($display); ?>">
  <input type="hidden" name="storedValue" value="<?php echo htmlspecialchars($storedValue); ?>">
  <input type="hidden" name="operator" value="<?php echo htmlspecialchars($operator); ?>">

ページを更新するたびにデータが初期化されてしまうのを防ぐため、<input type="hidden" name="display" value="...">のようにフォーム内に書き込み、次のリクエストでもPHPが同じ情報を受け取れるように工夫しています。

PHPのセッション機能($_SESSION)を利用しても状態を保持できますが、今回はフォームと隠しフィールドだけで完結させています。

単純なロジックはswitch文を使うとわかりやすい

switch ($button) {
        case 'AC':
            // 全リセット
            $display     = '0';
            $storedValue = '0';
            $operator    = '';
            break;

        case '±':
            // 符号反転
            if (is_numeric($display)) {
                $display = (string)((float)$display * -1);
            }
            break;

        case '%':
            // パーセント
            if (is_numeric($display)) {
                $display = (string)((float)$display / 100);
            }
            break;

        case '÷':
        case '×':
        case '−':
        case '+':
            // 演算子を入力 → 現在のdisplayを記憶し、演算子を保存
            $storedValue = $display;
            $operator    = $button;
            $display     = '0';  
            break;

        case '=':
            // = イコール → 記憶した値と現在のdisplayを演算
            if (is_numeric($storedValue) && is_numeric($display)) {
                $a = (float)$storedValue;
                $b = (float)$display;

                switch ($operator) {
                    case '+': $display = (string)($a + $b); break;
                    case '−': $display = (string)($a - $b); break;
                    case '×': $display = (string)($a * $b); break;
                    case '÷':
                        if ($b == 0) {
                            $display = 'Error'; // 0割り
                        } else {
                            $display = (string)($a / $b);
                        }
                        break;
                }
            }
            // 演算子はクリア
            $operator = '';
            break;

        default:
            // 数字・小数点入力の場合
            // displayが"0"または"Error"だった場合は置き換える
            if ($display === '0' || $display === 'Error') {
                $display = ($button === '.') ? '0.' : $button;
            } else {
                $display .= $button;
            }
            break;
    }

押されたボタンの種類に応じて分岐しているため、switch ($button)で各ケース(case 'AC': ...)を列挙するとスッキリしたコードにできます。

switch文は初学者でも直感的に理解しやすい記述方法なので、同じ処理でもいくつかの記述方法を使い分けて可読性の高いコーディングを心がけるようにしていきましょう。!

まとめ:簡易的なコーディングから慣れていこう!

今回は、HTML/CSS/PHPを使って「動く計算機アプリ」を実装した例を紹介しました。

実際に自分の手で作成したアプリが動く姿を見ると、「もっといろんな機能を実装してみたい!」「もっと複雑な処理を組んでみたい!」と思うようになってくることでしょう。

まずは簡単なロジックで動くアプリを作成してみて、そこから応用的に様々な機能を盛り込んでいくのが一番勉強になります。

簡単に情報が手に入る時代ではありますが、実際に手を動かして自分なりのアプリもぜひ作成してみてくださいね。

次回は、「動く計算機アプリ」をJavaで実装した例を紹介していきますので、気になる方はぜひそちらも確認してみてください!

目次