質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.59%

PHPでの電卓再現(表示部分の処理)

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,436

score 15

前提・実現したいこと

phpのみで動く電卓を作成しています。
機能としては、一般的な電卓の計算機能と、演算子を入力したら、その演算子を表示させる(例:5+10=15の時なら、+を入力したら次の10の1を入力するまで、表示したままにする。)

ソースコード

<?php  
//変数設定  
$f_num = $_POST['f_num'];  
$s_num = $_POST['s_num'];  
$input_num = $_POST['input_num'];  
$ope = $_POST['ope'];  
$button = $_POST['button'];  
$s_button = $_POST['s_button'];  

if (isNumBtn($button) || empty($button)) {  
    if (isOpeBtn($s_button)) {  
        $s_num = $f_num;  
        if (preg_match('/\./', $button)) {  
            $f_num = '0.';  
        } else {  
            $f_num = $button;  
        }  
    } else {  
        $f_num = $f_num . $button;  
    }  

    $input_num = $f_num;  
} else {  
    switch ($button) {  
        case 'C':  
            $f_num = '';  
            $s_num = '';  
            $input_num = '';  
            $ope = '';  
            break;  
        case '+/-':  
            $f_num = -$f_num;  
            break;  
        case '%':  
            $f_num = $f_num / 100;  
            break;  
        default:  
            if (!empty($s_num) && (preg_match('/=/', $button) || (isOpeBtn($button) && isNumBtn($s_button)))) {  
                switch ($ope) {  
                    case '+':  
                        $f_num = $s_num + $f_num;  
                        break;  
                    case '−':  
                        $f_num = $s_num - $f_num;  
                        break;  
                    case '✕':  
                        $f_num = $s_num * $f_num;  
                        break;  
                    case '÷':  
                        $f_num = $s_num / $f_num;  
                        break;  
                    default:  
                        break;  
                }  
            }  
            $s_num = $input_num;  
            $ope = $button == '=' ? $ope : $button;  
            break;  
    }  


}  

$s_button = $button;  

function convertDispNum($num) {  
    preg_match('/(-?)(\d+)(\.?\d*)/', $num, $matches);  

    return $matches[1] . number_format($matches[2]) . $matches[3];  
}  
function isOpeBtn($btn) {  
    return preg_match('/(+|−|✕|÷)/', $btn);  
}  

function isNumBtn($btn) {  
    return preg_match('/(\d|\.)/', $btn);  
}  
?>  

<!DOCTYPE html>  
<meta charset="UTF-8">  
<html>  
<head>  
    <title>電卓</title>  
</head>  
<body>  
<h2>Calculator</h2>  
</p><?php echo $f_num, $ope ?></p>  
<form action="?" method="post">  
    <input type="hidden" name="f_num" value="<?php echo $f_num; ?>" />  
    <input type="hidden" name="s_num" value="<?php echo $s_num; ?>" />  
    <input type="hidden" name="input_num" value="<?php echo $input_num; ?>" />  
    <input type="hidden" name="s_button" value="<?php echo $s_button; ?>" />  
    <input type="hidden" name="ope" value="<?php echo $ope; ?>" />  
    <table>  
        <tr>  
            <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>  
            <td><button type="submit" name="button" value="÷">÷</button></td>  
        </tr>  
        <tr>  
            <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>  
            <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>  
            <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>  
            <td colspan="2"><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="="></button></td>  
        </tr>  
</form>  
</body>  
</html>  

````````````````````````````````````````````````````````````````````````

質問内容

以上のソースコードだと、演算子がずっと残ったままになってしまいますが、上記の処理をさせたい場合、どのようにすればよろしいでしょうか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • stdio

    2019/04/18 11:31

    少しは考えて下さい。どこかに答えのあるような質問にまともに答える意味が果たしてあるのだろうかと?機能の改善したいならまず思い当るところをすべてやってから質問して来て下さい。
    描画のしているであろう部分の更新を演算子が入力された時は更新しないようにするとか、方法はいくらでもあるはずです。

    キャンセル

  • ruka02141

    2019/04/18 11:34

    stdio様
    あなたがまともに答える意味がないと思うなら、無視されて結構ですよ
    私があなたに直接お願いしてるわけではないので、どうぞお引取りください。

    キャンセル

  • m.ts10806

    2019/04/18 12:12 編集

    stdioさんの言い方はあれですけど「どこまで考えて何を試したかこの内容では伝わらないよ」ということだと思います。
    それはそれで前向きに捉えて受け取っても良いのではないでしょうか。
    現在の内容だと的確なアドバイスが得られにくいのは確かですし、機能改善のためおっしゃってはいますが、実際に「演算子が出続ける」という仕様、設計ではないのでしたら、それは一般的な電卓からすると期待する挙動ではないのでバグです。

    キャンセル

回答 3

+5

そういった課題を出してもらえるなんていい会社だ(小声)
回答ではないのでこちらに失礼します。ちょっと長くなったので、やっぱり回答欄に。

mts10806さんが記載されている通り、課題であれば答えを教えるのは違うかなと思います。
ぶち当たった壁から問題発生の事象を推測し、問題に対する課題を立て、課題を解決するための思考をするための思考ロジックを養うようにしてください。

本題でもないんですが、課題ということは研修担当の方がいらっしゃるんですよね?
ということは、研修担当はruka02141さんが書かれたコードをレビューするはずです。
ruka02141さんがどういう意図で、この処理を書いたのか、命名規則は何を基準につけたのか等々ソースから読み取らないといけません。
しかし研修担当の方も本来の業務の傍らruka02141さんの新人研修を担当されているはずで、時間がいくらあっても足りない状況かと思います。

はい。長々と書きましたが、コメントを残しましょう。(たったこれだけ)

ソースを見る限りだと、変数や処理がパッと見、なんの役割を担っているかわかりずらいです。(もちろん読めばわかる)
ご自身が数日後にこのソースを見返した時に、覚えていられますか?
おそらく綺麗サッパリ忘れているでしょう。
これはあくまで私が気をつけていることですが、数日後ないし明日の自分が見返しても、わかるor思い出せるように、備忘録程度のコメントはつけるべきかと思います。(コメントを付けすぎると可読性が落ちそうとかあるので、ケースバイケースですが)
そういったDOCは、第三者がruka02141さんが書かれたソースを読み解く時に、理解の助けになります。
是非、コメントを残してあげるように、ヤサシサニウムをしょほうして

※ここまで書きましたが、teratail掲載のためコメントを消されているようでしたら恐縮です。

後、改修する要件は、明確にかつ明示的にしましょう。
何をどうしなければならないのかの前に、今の電卓の処理がどういったフローで実行されているのか。を整理するだけでも、どのように改修したら良いか。が、見えてくるはずです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/18 11:32

    コメントありがとうございます。
    専門以外の一般大学出身ため、プログラミングの知識がなく、質問の仕方もまだわからない状況なので、Bernadotte様の指摘は本当にありがたいものです。
    以降は指摘してくださったことを念頭に勉強していきたいとい思います。

    キャンセル

+3

大前提:
質問するときのヒント」にあるように「課題や仕事を無償でやってもらえる場ではありません」

「課題だろうな」と回答者に印象付けた時点で有益なアドバイスを得らえる機会を失することにもなりかねません。
特に新人研修課題であれば上司なり先輩なりが本来の確認先です。
もし、「考える力をつけさせるための課題」だとしたら、質問サイトでその課題を解決しようとする行為が良いかどうかは一考の必要があります。

「思考するエンジニアの為のQ&Aコミュニティ」「具体的にプログラミングで困っている質問をする場所」であって「宿題・課題代行サイト」ではないからです。

もちろん、「宿題・課題について質問するな」というわけではありません。
サイトの大前提となる部分を理解したうえで、「課題代行依頼ではない」というところが伝わるように気を付ける必要があります。

良い使い方は「9割できててあと1割がどうしても手が届かない」というときの1割を埋める使い方です。あくまで理想論なので参考まで。
(自身の質問の仕方を見直す指標になると思います)


おそらく本問題とは関係ないですが、actionに?は意味がないです。
「自身に送信」なのでしたらaction=""とするかaction属性自体なくても良いと思います。

ユーザー入力を画面出力時にはhtmlエスケープ必須。
参考記事:サニタイズ/入力値検証/エスケープの考え方

本題

まず、画面を表示したときには$_POSTは送られていません。
ゆえに、画面アクセスした際には下記のようにNoticeが出ます。

Notice: Undefined index: f_num in XXXX.php on line 3

Notice: Undefined index: s_num in XXXX.php on line 4

Notice: Undefined index: input_num in XXXX.php on line 5

Notice: Undefined index: ope in XXXX.php on line 6

Notice: Undefined index: button in XXXX.php on line 7

Notice: Undefined index: s_button in XXXX.php on line 8

意味は調べてください。珍しいものではないです。
表示されていないのでしたらエラー表示をOnにして確認してください。

いずれにしても「POST送信されていたら処理を行う」のが前提なので、
画面表示に使うREQUEST METHODを確認するか、$_POSTの存在チェックで分岐させましょう。

$f_num = '';
//以下略 画面表示に利用している変数は全て初期化しておくこと

if($_SERVER $_SERVER ['REQUEST_METHOD'] === 'POST'){
    $f_num = $_POST['f_num'];
//中略

}
//今のコードだとfunctionの手前がいいかなと

または

if(count($_POST)>0){
    $f_num = $_POST['f_num'];
//中略

}

あと、特に機能改善のためであればリファクタリング兼ねてるようにも思いますので、
functionは外だししましょう。別のphpに書いてincludeです。
※本来はcomposer導入してnamespaceで管理すべきですが、最初の段階として。

コード的な順序で後に書いてあるfunctionを使うような流れは私からするとちょっと違和感強いです。
「定義してあるものを使う」という流れにする必要がありますので、別ファイルにしないにしてもできればプログラムの冒頭に書きましょう。

あと、きちんとコメントを書くことですね。

もう1つ結構忘れられがちなのが「html”ソース”を確認すること」です。
「画面に出てるのでわかるだろ」って?思うかもしれませんが、そうではないです。
hiddenに設定している値が想定している値が入ってるかどうか、画面から分かりますか?
「デベロッパーツールから確認すればわかるだろ」って?思うかもしれませんが、そうではないです。
デベロッパーツールはブラウザ側が結構いい感じに補完してくれてます。
実際に出力されているコードとは異なり、ブラウザが勝手にstyle入れて微調整してくれていることもあります。

なので「ソースを表示」からきちんと出力内容を確認するようにしてください。
phpはあくまで出力を行うだけでどのような手段で出力内容を確認されるか知りません。
ブラウザかもしれない、コマンドラインかもしれない、その他etc.

なので「出力内容そのまま」を確認できるブラウザの「ソースの表示」による確認は必須です。


あとは地道なデバッグです。

「ずっと残っている」ということは、演算子が不要になるタイミングできちんと空文字化がされていないということになりますよね。
ではどこで演算子が不要となるでしょうか?

そこは「仕様」部分になります。
「こうなると不要となる」という条件はあくまで設計段階で決められるべきところです。
「どう書いたら演算子を消せるか」というコードベースで考えるのではなく「どこで演算子表示をなくすべきか」という設計ベースで考えましょう。

演算子が不要となるタイミングはいつですか?

決まっていないのでしたら、それを決めて(設計に組み込んで)、その通りに組むだけです。

プログラムは組んだ通りにしか動きません。
導入されていない機能を忖度してうまいことやってくれるなんてことは絶対にありません。
「ここ!」というのを見極めて適切な設計を行い、それにそった適切なコードを入れてください。


IntelliJ IDEA は使ったことないですがhtmlの構文チェック機能は入ってるのでしょうか?
本筋とは関係ないですが列挙しておきます。

  • metaタグがhead内に入ってない
  • table閉じられてない
  • </p> ~ </p> ←開始してない?
  • <!DOCTYPE html>より前に空行はないほうがいい(ほぼ私見ですけど)

IDEに機能がないのでしたらWeb上のサービスを利用するのも有用です。

正しいhtmlを組まないと今後JavaScriptなど利用する際に正しく動かない要因になりますし、CSSも含めたレイアウトの際には問題の切り分けを困難にします。


蛇足:
非常に細かいですが、行末にほぼ必ずある'  '←この半角スペース2つは何でしょう?
特に何もないのでしたら削られたほうが良いです。動作に影響はないですが、ファイルサイズに多少影響があります(ちりも積もれば・・・)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+1

87行目を以下にするといかがでしょうか

    <p><?php echo $f_num; if (isOpeBtn($button)){echo $ope;} ?></p>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/18 11:35

    kokemomo.sour様
    回答ありがとうございます。きちんと処理されました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る