Чат PHP-разработчиков
Как сделать калькулятор на PHP

Пишем калькулятор на PHP

Всем привет! Мы с вами изучили 2 типа запросов: GET и POST. Они позволяют нам отправлять данные на сервер, благодаря чему мы можем с ним «общаться». Мы рассмотрели несколько простейших примеров. В этом уроке для закрепления материала мы с вами напишем свой калькулятор!

Прежде чем приступить к его созданию, давайте обговорим то, что он должен уметь. Пусть наш калькулятор будет принимать на вход 2 числа, и операцию, которую над этими числами нужно совершить (сложение, вычитание, умножение, деление). После этого он будет выводить нам получившееся выражение и его результат.

Итак, вот так будет выглядеть форма для ввода исходных данных:
Форма калькулятора

А вот так будет выглядеть страница с результатом:
Результат вычислений

Давайте теперь спроектируем, где что будет лежать. Я предлагаю сделать такую архитектуру:

  • index.php – здесь будет храниться форма, в которой мы будем заполнять исходные данные
  • result.php – здесь будет храниться шаблон, который будет выводить результат вычислений
  • calc.php – файл, в котором будет храниться непосредственно вся бизнес-логика нашего приложения.

Шаблоны калькулятора

Итак, приступим. Давайте начнём с формы. Она будет содержать в себе:

  • 2 input’а, в которые мы будем записывать аргументы;
  • select, который позволит нам выбрать одну из доступных операций;
  • кнопку, для отправки формы.

Я приведу здесь пример формы, в которой будет только две возможные операции: сложение и вычитание.

Код доступен только после покупки курса PHP для начинающих.

Здесь вам всё должно быть знакомо. Если нет — повторите уроки с формами в курсе HTML.

Мы видим, что данная форма отправляет GET-запрос на адрес /result.php. Как мы уже решили, там будет находиться шаблон для вывода результата вычислений.

Вот пример кода, который получился у меня:

Код доступен только после покупки курса PHP для начинающих.

Как видим, здесь всё предельно просто — в переменную $result присваивается значение, возвращаемое из файла calc.php. Затем мы просто-напросто выводим результат из этой переменной.

Бизнес-логика калькулятора

Теперь самое интересное — написать бизнес-логику. Создаём файл calc.php и начинаем думать.

Первое, в чём нам стоит убедиться, есть ли вообще какие-либо данные в GET-запросе. Для этого проверяем массив $_GET на пустоту:

Код доступен только после покупки курса PHP для начинающих.

Сейчас, если перейти по адресу http://myproject.loc/result.php, мы увидим соответствующий результат:
Исходные данные пусты

Далее, нам стоит проверить, что из формы переданы x1, x2 и operation.

Код доступен только после покупки курса PHP для начинающих.

Можно теперь вернуться на форму с исходными данными и заполнить её какими-нибудь данными:
Заполняем форму исходными данными

Если теперь нажать на кнопку отправки формы, мы увидим, что никаких ошибок в форме результата теперь не возникло:
Результат без ошибок

Вместо этого мы теперь видим число 1. Это результат того, что в файле calc.php мы ничего не вернули, но при этом попытались это «ничего» с помощью функции require присвоить в переменную $result. Единица вернулась нам, потому что файл был успешно подключен, но ничего не вернул. Это значение по умолчанию.

Попробуем теперь убрать один из аргументов в форме:
Убираем аргумент из исходных данных

Если мы отправим запрос сейчас, то увидим соответствующую ошибку:
Ошибка при пустых аргументах

Ну что, теперь мы знаем, что данные у нас проверяются, можно с ними и поработать.

Давайте для удобства сделаем 2 переменные $x1 и $x2 и положим в них значения из GET-запроса.

Код доступен только после покупки курса PHP для начинающих.

Давайте теперь составим выражение, которое мы будем вычислять. Его мы просто будем выводить для наглядности.

Код доступен только после покупки курса PHP для начинающих.

Теперь вернёмся на форму и снова введём корректные аргументы. После этого отправим её и увидим, что на странице с результатом появилось выражение, результат которого мы будем считать.
Выражение из исходных данных

Дело осталось за малым — нужно только посчитать результат.

Для того, чтобы определить, какое действие нужно совершить с аргументами, воспользуемся конструкцией switch-case.

В результате получаем такое содержимое calc.php.

Код доступен только после покупки курса PHP для начинающих.

Давайте теперь снова отправим форму и посмотрим на результат.
Калькулятор готов

Получили простейший калькулятор, который умеет складывать и вычитать. Разумеется, это лишь простейший прототип. Довести его до ума вы сможете сами, а в домашнем задании вас ждут наводящие вопросы, которые помогут найти ошибки, содержащиеся в приведенном коде.

Домашнее задание
  1. Попробуйте в качестве одного из аргументов передать 0. Какой получился результат? Почему так? Дополните код так, чтобы можно было передавать 0.
  2. Усовершенствуйте калькулятор так, чтобы он умножал и делил.
  3. Что произойдёт, если поделить на ноль? Добавьте обработку такой ситуации.
  4. Что произойдёт, если в качестве аргумента передать вместо числа строку? Сделайте так, чтобы в качестве аргументов можно было отправить только числа.
  5. Какие ещё недостатки есть у этого кода? Как можно нарушить его работу? Что можно улучшить?

В комментариях пишите только содержимое файла calc.php. Код из файлов index.php и result.php приводить не нужно.

Читайте также
Комментарии (64)


BlackWood

1)

if (($_GET['x1'] === '') || ($_GET['x2'] === '')) {
    return 'Аргументы не переданы';
}
BlackWood

2)

  switch ($_GET['operation']) {
    case '+' :
        $result = $x1 + $x2;
        break;
    case '-' :
        $result = $x1 - $x2;
        break;
    case '*' :
        $result = $x1 * $x2;
        break;
    case '/' :
        $result = $x1 / $x2;
        break;
    default:
        return 'Операция не поддерживается';
}
BlackWood

3)

    case '/' :
        $result = $x2 != 0 ? ($x1 / $x2) : 'На ноль делить нельзя';
        break; 
ivashkevich

Отлично! Все правильно.

marquise

Проверка на строку :

if ((gettype($x1)=== "string") && (gettype($x2) === "string")){
    return 'Введите числа';
}
else{
    $expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';
        switch ($_GET['operation']) {
            case '+':
                $result = $x1 + $x2;
                break;
            case '-':
                $result = $x1 - $x2;
                break;
            case '*':
                $result = $x1 * $x2;
                break;
            case '/':
                $result = $x1 / $x2;
                break;
            default:
                return 'Операция не поддерживается';
        }

        return $expression . $result;
}
ivashkevich

Не пойдёт, в переменной $_GET['что-то'] всегда будет строка. Попробуйте ещё варианты.

P.S. else здесь лишний: если условие выполнится, то сработает return и код дальше не будет выполняться. Достаточно писать:

if (!тут_проверка_на_число){
    return 'Введите числа';
}

тут_просто_выполняем_код_дальше
KeeF3ar

4 в индексе

 <label for="x1"></label><input type="number" name="x1" id="x1">

в calc.php

<?php
if (empty($_GET)) {
    return 'Ничего не передано!';
}

if (empty($_GET['operation'])) {
    return 'Не передана операция';
}

if (($_GET['x1'] == '') || ($_GET['x2'] == '')) {
    return 'Аргументы не переданы';
}

$x1 = intval($_GET['x1']);
$x2 = intval($_GET['x2']);

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if ($x2 === 0) {
            return 'На ноль делить нельзя';
        } else $result = $x1 / $x2;
        break;
    default:
        return 'Операция не поддерживается';
}

return $expression . $result;
ivashkevich

Очень хорошо, что позаботились о клиентской стороне! А ещё можно было проверить, является ли переданное значение числом с помощью is_numeric().

vadymbilyi@gmail.com

а можно использовать ctype_digit() вместо is_numeric()?

ivashkevich

Тогда дробные числа не пройдут (содержат точку, а не только цифры)

1nSide

Сделал, вроде все работает

<?php

if (empty($_GET)){
    return 'Ничего не переданно';
}

if (empty($_GET['operation'])){
    return 'Операция не переданна';
}

if ($_GET['x1'] === ''|| $_GET['x2'] === ''){
    return 'Аргументы 1 или 2 не переданны';
}

$x1 = $_GET['x1'];
$x2 = $_GET['x2'];
$operations  = $_GET['operation'];

if (is_numeric($x1) && is_numeric($x2)){
     switch ($operations){
        case '+':
            $result = $x1 + $x2;
            break;
        case  '-':
            $result = $x1 - $x2;
            break;
        case  '/':
            $result = $x2 != 0 ? ($x1 / $x2) : 'На ноль делить нельзя';
            break;
        case  '*':
            $result = $x1 * $x2;
            break;

        default:
            return 'Операция не поддерживается';
    }
} else {
    return 'Введите число';
}

$expression = $x1 . ' ' . $operations . ' ' . $x2 . ' = ';

return $expression . $result;
ivashkevich

Всё в общем-то очень хорошо)

Из улучшений:

  • Представьте, что в форме пропадает поле x1 и при её отправке вообще прропадает query-параметр x1=что-то
    Тогда при выполнении, там где происходит обращение к $_GET['x1'], возникнет ошибка.
    Чтобы этого избежать, стоит воспользоваться функцией array_key_exists() или isset() - так вы сможете убедиться, что такой ключ в массиве существует. А если нет - напишете соответствующую ошибку.
  • Переменная $operations на деле содержит только одну операцию, значит - $operation
  • При обработке ошибок мы не выводим исходное выражение - если операция не поддерживается, то сразу об этом пишем, без склейки с $expression. Для однообразия при делении на ноль стоит делать также - добавить if и вызывать в нём сразу return, если x2 === 0.
1nSide

Так?

<?php
// проверяет через функцию пустой метод гет или нет
if (empty($_GET)){
    return 'Ничего не переданно';
}
// проверяем через функцию пустой метод гет с массивом операция 
if (empty($_GET['operation'])){
    return 'Операция не переданна';
}
// проверяем нахождения ключа в массиве метода гет
if (isset($_GET['x1']) && isset($_GET['x2'])){
    $x1 = $_GET['x1'];
    $x2 = $_GET['x2'];
} else return 'Ключу аргумента отсутсвоет';

    $operation = $_GET['operation'];
// проверка на то чтобы пользователь мог записовать только числа
if (is_numeric($x1) && is_numeric($x2)){
     switch ($operation){
        case '+':
            $result = $x1 + $x2;
            break;
        case  '-':
            $result = $x1 - $x2;
            break;
        case  '/':
            if($x2 != 0){
               $result = $x1 / $x2;
            } else {
                return 'На ноль нельзя делить';
            }
            break;
        case  '*':
            $result = $x1 * $x2;
            break;

        default:
            return 'Операция не поддерживается';
    }
} else {
    return 'Введите число';
}
// создаем переменную и записываем переменные в нужной последовательности
$expression = $x1 . ' ' . $operation . ' ' . $x2 . ' = ';
// вывод результата
return $expression . $result;
ivashkevich

Да, теперь все корректно. Но содержимое после if и else советую всегда помещать внутрь фигурных блоков, даже если это одна строка.

А switch можно написать вне if, это позволит избавиться от лишней вложенности. Просто сделайте проверку на ошибки отдельным условием:

if (!is_numeric($x1) || !is_numeric($x2)) {
    return 'x1 и x2 должны быть числами';
}

switch ...

Понимаете, что проще стало? Сначала проверили данные на корректность, а потом уже с ними спокойно работем, избегая слишком громоздких условий.

1nSide

Все сделал, не знаю что еще добавить можно) все работает)

<?php

if (empty($_GET)){
    return 'Ничего не переданно';
}

if (empty($_GET['operation'])){
    return 'Операция не переданна';
}

    $x1 = $_GET["x1"] ?? null;
    $x2 = $_GET["x2"] ?? null;
    $operation = $_GET['operation'];

if ($x1 === null || $x2 === null){
    return 'Ключу аргумента отсутсвоет';
}

if (!file_exists(__DIR__ . '/calc.php')){
    return 'Ошибка файла';
}

if (!is_numeric($x1) || !is_numeric($x2)){
    return 'Введите число';
}

     switch ($operation){
        case '+':
            $result = $x1 + $x2;
            break;
        case  '-':
            $result = $x1 - $x2;
            break;
        case  '/':
            if($x2 != 0){
               $result = $x1 / $x2;
            } else {
                return 'На ноль нельзя делить';
            }
            break;
        case  '*':
            $result = $x1 * $x2;
            break;

        default:
            return 'Операция не поддерживается';
    }

$expression = $x1 . ' ' . $operation . ' ' . $x2 . ' = ';

return $expression . $result;
ivashkevich

Всё супер. Только не понял, для чего вы внутри calc.php проверяете, что он существует. Это лишнее. Все остальное - огонь!

ppixx@mail.ru

А в степень почему-то не получается с помощью pow, только ** - подскажите почему так?

ivashkevich

Потому что в PHP нет функции pow(), но есть оператор ** =)

andropij
<?php

if (empty($_GET)) {
    return "nothing";
}

if (empty($_GET['operation'])) {
    return "no operation";
}

if (($_GET['number1']=='') || ($_GET['number2']=='')) {
    return "nothing";
}

$x1 = $_GET['number1'];
$x2 = $_GET['number2'];
$operation = $_GET['operation'];

$expression = $x1 . ' ' . $operation . '  ' . $x2 . ' = ';

switch ($operation) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '/':
        if ($x1 != 0) {
            $result = $x1 / $x2;
        } else {
            return 'на ноль делить нельзя';
        }
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    default:
        return 'Операция не поддерживается';
}
return $expression . $result;

единственное. Проблему со string решил так:

<input type="number" name="number1">
<input type="number" name="number2">

ivashkevich

Ок, всё норм. Речь шла о проверке на бэкенде - функция is_numeric() позволяет проверить, что в переменной именно числовое значение.

tvan@yandex.ru

Пока так и не получилось прибавить 0. Пишу позже, может кому поможет. Разобрался, почему не получалось, потому-что проверял x1 и x2 на empty(), и если вводил 0, то php считал, что поле пустое

ivashkevich

Ага, всё правильно, первое задание засчитано. А как в итоге сделал?

tvan@yandex.ru

Спасибо за замечательный курс. Все получилось, но пришлось подсмотриват в ответах других участников.

<?php
if (empty($_GET))
    return " Ничего не передано!";

if (empty($_GET['operation']))
    return " не передана операция";

if (($_GET['x1'] === null) || ($_GET['x2'] === null)) 
    return 'Аргументы не переданы';

    if (!is_numeric($_GET['x1']) || !is_numeric($_GET['x2']))
        return ' Введите числа';

    if (isset($_GET['x1']) && isset($_GET['x2'])){
    $x1 = intval($_GET['x1']);
    $x2 = intval($_GET['x2']);
    }
    $expression = $x1 .' '.$_GET['operation'].' '.$x2.' = ';

    switch ($_GET['operation']){
        case '+':
            $result = $x1 + $x2; break;
        case '-':
            $result = $x1 - $x2; break;
        case '*':
            $result = $x1 * $x2; break;
        case '/' :
            $result = $x2 != 0 ? ($x1 / $x2) : 'На ноль делить нельзя'; break; 

        default:
           return 'операция не поддерживается';

    }

    return $expression.$result;
?>
ivashkevich

Это абсолютно нормально, не забывайте в гугле и на stackoverflow тоже подглядывать.

DmitryGavrilov
<?php

if (empty($_GET)) {
    return "Ничего не передано, массив пустой";
}

if (empty($_GET['operation'])) {
    return 'не передана операция';
}

//Теперь можно передать ноль
if (($_GET['x1'] == '') || ($_GET['x2'] == '')) {
    return 'Аргументы не переданы';
}

if (!is_numeric($x1) || !is_numeric($x2)) {
    return 'Нельзя вводить строковые значения';
}

//… задали переменные для массива гет
$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

//Для наглядности выводим значения x1 и x2 =
$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

// собственно сами вычисления
switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if ($x2 != 0) {
            $result = $x1 / $x2;
        } else {
            return 'На ноль нельзя делить!';
        }
        break;

    default:
        return "операция не поддерживается";

}

return $expression . $result;
ivashkevich

По поводу 'Нельзя вводить строковые значения' - не совсем правда. В коде проверка только на то, что это не число. Это ещё не значит, что там строка. Правильнее будет сказать именно о том, что значения должны быть числовыми.

В остальном - отлично!

DmitryGavrilov

Спасибо! Учту!

Nikolas

Ты случаем не пропустил закрывающий тек </label> для id="operation"?
Проверка на пустоту $_GET и сопутствующее ему выполнение бессмысленны,т.к. селектор по умолчанию предлагает первый вариант и при нажатии кнопки посчитать, это значение передастся.
Для чего задавать label если мы оставляем их пустыми?
Нужно ли в логике в конструкции switch задавать default, если у нас селектор содержит только два варианта?

ivashkevich

Да, label лишние, убрал. Спасибо.

Проверка на пустоту не бессмысленна - нельзя доверять тому, что придёт от клиента. Нет гарантии что пользователи будут отправлять данные на бекенд исключительно из "правильной" формы. Ничто не мешает им создать свою форму с плохими данными и завалить ваш бекенд ошибками.

В switch лучше всегда добавляйте секцию default - в ней можно обрабатывать внештатные ситуации, когда пришли данные, которых быть не должно.

Nikolas

Понял,спасибо! Отличный практический урок :)

dom1r

Мой топовый код :D

<?php

if (empty($_GET)) {
    return 'Ничего не передано';
}

if (empty($_GET['operation'])) {
    return 'Не передана операция';
}

//Обработка нулевых аргументов
if (empty($_GET['x1']) && $_GET['x1'] !== '0' || empty($_GET['x2']) && $_GET['x2'] !== '0') {
    return 'Не переданы аргументы';
}

//Обработка деления на 0
if (($_GET['x1'] !== '0' && $_GET['x2'] == '0') && $_GET['operation'] == '/') {
    return 'Деление на ноль!';
}

//Обработа строковых аргументов

if (!is_numeric($_GET['x1']) || !is_numeric($_GET['x2'])) {
    return 'Переданные значения не являются числом';
}

$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

$expression = "{$x1} {$_GET['operation']} {$x2} = ";

switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        $result = $x1 / $x2;
        break;
    default:
        return 'Опеация не поддерживается';

}

return "{$expression} {$result}";
ivashkevich

Да, хорошо =)
Единственное, вместо

//Обработка нулевых аргументов
if (empty($_GET['x1']) && $_GET['x1'] !== '0' || empty($_GET['x2']) && $_GET['x2'] !== '0') {
    return 'Не переданы аргументы';
}

я бы написал:

if (!isset($_GET['x1']) || !isset($_GET['x2'])) {
    return 'Не переданы аргументы';
}
Fox-24

Благодарю!

<?php
if (empty($_GET)) {
    return 'Ничего не передано!';
}

if (empty($_GET['operation'])) {
    return 'Не передана операция';
}

if ('' == $_GET['x1'] || '' == $_GET['x2']) {
    return 'Не переданы аргументы';
}

$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

if (is_numeric($x1) && is_numeric($x2)) {

    if ($_GET['operation']) {

        switch ($_GET['operation']) {
            case '+':
                $result = $x1 + $x2;
                break;
            case '-':
                $result = $x1 - $x2;
                break;
            case '*':
                $result = $x1 * $x2;
                break;
            case  '/':
                $result = $x2 != 0 ? ($x1 / $x2) : 'На ноль делить нельзя';
                break;
            default:
                return 'Операция не поддерживается';
        }

    }
} else {
    return 'Пожалуйста, введите число';
}

return $expression . $result;
ivashkevich

Если с формы сейчас убрать input x1 или x2, то скрипт посыпется с warning-ами, из-за того что в массиве $_GET вообще нет ключей x1 и x2. Попробуйте исправить.

Fox-24

Да, на сколько я знаю надо всегда проверять передаются ли параметры. Спасибо за замечание.

if (isset($_GET['x1']) && isset($_GET['x2'])) {
    $x1 = $_GET['x1'];
    $x2 = $_GET['x2'];
} else return 'Нет ключей. Обратитесь к разработчику этого калькулятора или попробуйте снова.';

Видимо упустил когда редактировал этот код:

if ('' == $_GET['x1'] || '' == $_GET['x2']) {
    return 'Не переданы аргументы';
}
ivashkevich

Окей, и еще один совет: всегда используйте фигурные кавычки для конструкций if-else, даже если это одна строка.

ArtemijeKA
if (empty($_GET)) {
    return 'Ничего не передано!';
}
if (empty($_GET['operation'])) {
    return 'Не передана операция';
}
if (!is_numeric($_GET['x1']) || !is_numeric($_GET['x2'])) {
    return 'Не переданы числовые аргументы';
}
$x1 = (float)$_GET['x1'];
$x2 = (float)$_GET['x2'];
$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';
switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if ($x2 === (float)0) {
            $result = 'На ноль делить нельзя!';
        } else {
            $result = $x1 / $x2;
        }
        break;
    default:
        return 'Операция не поддерживается';
}
return $expression . $result;
ivashkevich

Если не будут переданы x1 или x2, будет ошибка, попробуйте исправить.

ArtemijeKA

Вроде нет ошибки. А только предупреждение выводится: "Не переданы числовые аргументы!".

ivashkevich

А если их совсем из формы убрать?

ArtemijeKA

Да при пустых input'ах я проверял.

Dilik
if (empty($_GET)) {
    return 'Nothing has been transferred!';
}
if (empty($_GET['operation'])) {
    return 'Operation not transferred';
}
if (($_GET['x1' === '']) || ($_GET['x2'] === '')) {
    return 'Arguments are not passed';
}

$x1 = $_GET['x1'];
$x2 = $_GET['x2'];
if (!is_numeric($x1)) {
    return 'Input interger number';
}
if (!is_numeric($x2)) {
    return 'Input interger number';
}
if ($_GET['$x1'] = '0' || $_GET['$x2'] = '0') {
    return $x1 = 0 || $x2 = 0;
}

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        $result = $x2 != 0 ? ($x1 / $x2) : 'you can not divide it by zero';
        break;
    default:
        return 'Operation not supported';
}
return $expression . $result;
ivashkevich
if (($_GET['x1' === '']) || ($_GET['x2'] === '')) {

Вот здесь будет ошибка, если аргументы в форме вообще отсутствовали. Нужно проверять с помощью isset, затем проверить с помощью is_numeric, привести переменные к float, и только после этого сравнивать с 0 (не строкой, а числом).

if (!is_numeric($x1)) {
    return 'Input interger number';
}

is_numeric не гарантирует, что число будет именно целым, текст ошибки некорректен.

Benya
<?php

if (empty($_GET)) {
    return 'Ничего не переданно!';
}

if (empty($_GET['operation'])) {
    return 'Не переданна операция';
}

if (($_GET['x1']==='') || ($_GET['x2']==='')) {
    return 'Не переданны аргументы';
}

$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

if (!is_numeric($x1) || !is_numeric($x2)) {
    return 'Введите числа!';
}else {
    $expression = $x1 . '' .$_GET['operation'] . '' . $x2 . '=';

    switch ($_GET['operation']) {
        case '+':
            $result = $x1 + $x2;
            break;
        case '-':
            $result = $x1 - $x2;
            break;
        case '*':
            $result = $x1 * $x2;
            break; case '/':
        $result = $x2 != 0 ? $x1 / $x2 : 'Нельзя делить на 0';
        break;

        default:
            return 'Операция не поддерживается';
    }
}

return $expression . $result;
ivashkevich
if (($_GET['x1']==='') || ($_GET['x2']==='')) {
    return 'Не переданны аргументы';
}

Будет ошибка, если поля в форме вообще отсутствовали, нужно проверять с помощью isset.

SBTesla
<?php
// Проверяем переданны ли данные вобще
if (empty($_POST)) {
    return 'Ничего не передано';
}
// проверяем передана ли операция

if (empty($_POST['operation'])) {
    return 'операция не передана';
}

/* проверяем переданы ли аргументы, и проверяем числа это или нет.
проверяем можно ли передавать ноль */
if (($_POST['x1'] === '') || ($_POST['x2'] === '')) {
   return 'Не переданы аргументы';
}

if (is_numeric($_POST['x1']) || is_numeric($_POST['x2'])) {
} else {
    return 'Введите числовое значение';
}

/* создаем переменные  в которых будут лежать  наши
значения */

$x1 = $_POST['x1'];
$x2 = $_POST['x2'];

$output = $x1 . '' . $_POST['operation'] . '' . $x2 . '=';

switch ($_POST['operation']){
    case '+':
        $result = $x1 + $x2;
        break;
    case '-' :
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
        /* проверяем деление на ноль*/
    case '/':
        if ($x1 != 0) {
            return ' на ноль делить нельзя';
        }
        $result = $x1 / $x2;
        break;
    default:
        return 'операция не поддерживаеться';
}

return $output . $result;
vadymbilyi@gmail.com
<?php

if (empty($_GET)) {
    return 'Ничего не передано!';
}
if (empty($_GET['operation'])) {
    return 'Не передана операция';
}
if (($_GET['x1'] === '') || ($_GET['x2'] === '')) {
    return 'Аргументы не переданы';
}
if (!is_numeric($_GET['x1']) ||  !is_numeric($_GET['x2'])) {
    return 'В поле можно ввести только цифры';
}

$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '/':
        if ($x2 == 0){
            return 'На 0 делить нельзя!';
        }
        else {$result = $x1 /  $x2;}
        break;
    case '*':
        $result = $x1 *  $x2;
        break;
    default:
        return 'Операция не поддерживается';
}

return $expression . $result;
ivashkevich
if (($_GET['x1'] === '') || ($_GET['x2'] === '')) {
    return 'Аргументы не переданы';
}

Будет ошибка, если поля в форме вообще отсутствовали, нужно проверять с помощью isset.

lordbear53@gmail.com

Спасибо за урок! =)

Код из файла calc.php

<?php

if(empty($_GET))
{
    return 'Значений не передано!';
}
if(empty($_GET['operation']))
{
    return 'Операция не передана!';
}
if(empty($_GET['x1']) && $_GET['x1'] != 0 || empty($_GET['x2']) && $_GET['x2'] != 0)
{

}
if(gettype($_GET['x1']) === "string" || gettype($_GET['x2']) === "string" )
{
    return 'Введите числа!';
}

$x1= $_GET['x1'];
$x2 = $_GET['x2'];

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

switch ($_GET['operation'])
{
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if($x1 == 0 || $x2 == 0)
        {
            $result = 'На ноль делить нельзя'; //На самом деле выйдет бесконечность =)
        } else {
            $result = $x1 / $x2;
        }
        break;
    default:
        return 'Операция не подерживается';
}

return $expression . $result;

На счет того что добавить/улучшить:
1)Когда я попробовал ввести 2 - -2 у меня выдало "Введите числа"
2)Степень, корень, факториал

ivashkevich

Вот тут что-то не так:

if(empty($_GET['x1']) && $_GET['x1'] != 0 || empty($_GET['x2']) && $_GET['x2'] != 0)
{

}

Вот тут стоить использовать для проверки is_numeric (так как параметр из POST-запроса это почти всегда строка):

gettype($_GET['x1']) === "string"

$x1 может быть нулем

        if($x1 == 0 || $x2 == 0)
        {
            $result = 'На ноль делить нельзя'; //На самом деле выйдет бесконечность =)
        }
lordbear53@gmail.com

Переделал

<?php

if(empty($_GET) && $_GET['x1'] != 0 && $_GET['x2'] != 0)
{
    return 'Значений не передано!';
}
if(empty($_GET['operation']))
{
    return 'Операция не передана!';
}
if(!is_numeric($_GET['x1'])|| !is_numeric($_GET['x2']))
{
    return 'Введите числа!';
}

$x1= $_GET['x1'];
$x2 = $_GET['x2'];

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

switch ($_GET['operation'])
{
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if($x2 == 0)
        {
            $result = 'На ноль делить нельзя'; //На самом деле выйдет бесконечность =)
        } else {
            $result = $x1 / $x2;
        }
        break;
    default:
        return 'Операция не подерживается';
}

return $expression . $result;
ivashkevich
if(empty($_GET) && $_GET['x1'] != 0 && $_GET['x2'] != 0)

Если я передам два числа, отличные от нуля, то программа не будет работать. Вы хоть проверяйте, чтобы она хотя бы просто работала, прежде чем отправлять =)

lordbear53@gmail.com

Простите, я просто сидел в Универе на паре и почему-то подумал, что это вполне себе логичное решение =)

Вот робочий код ( как минимум у меня пашет =) )

<?php

if(empty($_GET) )
{
    return 'Значений не передано!';
}
if(empty($_GET['operation']))
{
    return 'Операция не передана!';
}
if(!is_numeric($_GET['x1'])|| !is_numeric($_GET['x2']))
{
    return 'Введите числа!';
}

$x1= $_GET['x1'];
$x2 = $_GET['x2'];

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

switch ($_GET['operation'])
{
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if($x2 == 0)
        {
            $result = 'На ноль делить нельзя'; //На самом деле выйдет бесконечность =)
        } else {
            $result = $x1 / $x2;
        }
        break;
    default:
        return 'Операция не подерживается';
}

return $expression . $result;
ivashkevich

Если на форме убрать поля x1 и x2, и отправить запрос, то скрипт вот здесь вывалит ошибку.

if(!is_numeric($_GET['x1'])|| !is_numeric($_GET['x2']))

Но этот скрипт должен корректно работать, независимо от формы - нельзя доверять тому, что форма будет корректной. Поэтому нужно проверять сначала, пришли ли эти значения вообще или нет. Для этого можно использовать функцию isset().

demyanovpaul@yandex.ru
  • Попробуйте в качестве одного из аргументов передать 0. Какой получился результат? Почему так? Дополните код так, чтобы можно было передавать 0.
    if (empty(isset($_GET['x1'])) || empty(isset($_GET['x2']))) {
    return 'Не переданы аргументы';
    }
  • Усовершенствуйте калькулятор так, чтобы он умножал и делил.
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if($x2 != 0)
            $result = $x1 / $x2 ;
        else
            return 'Простите, хорошие интерпритаторы на ноль не делят, а я очень хороший! =)';
        break;
  • Что произойдёт, если поделить на ноль? Добавьте обработку такой ситуации.
    case '/':
        if($x2 != 0)
            $result = $x1 / $x2 ;
        else
            return 'Простите, хорошие интерпритаторы на ноль не делят, а я очень хороший! =)';
        break;
  • Что произойдёт, если в качестве аргумента передать вместо числа строку? Сделайте так, чтобы в качестве аргументов можно было отправить только числа.
    if (!is_numeric(trim($_GET['x1'])) || !is_numeric(trim($_GET['x2']))) {
    return 'В параметры передана строка, а должно быть число, исправьте и повторите ввод снова!';
    }
  • Какие ещё недостатки есть у этого кода? Как можно нарушить его работу? Что можно улучшить?

От себя добавил чтобы при проверки на строку, очищал пробелы, так как интерпретатор сам приводит к числовым значениям даже если есть пробелы слева и справа

Весь код

<?php
if (empty($_GET)) {
    return 'Ничего не передано!';
}

if (empty($_GET['operation'])) {
    return 'Не передана операция';
}

if (empty(isset($_GET['x1'])) || empty(isset($_GET['x2']))) {
    return 'Не переданы аргументы';
}

if (!is_numeric(trim($_GET['x1'])) || !is_numeric(trim($_GET['x2']))) {
    return 'В параметры передана строка, а должно быть число, исправьте и повторите ввод снова!';
}

$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if($x2 != 0)
            $result = $x1 / $x2 ;
        else
            return 'Простите, хорошие интерпритаторы на ноль не делят, а я очень хороший! =)';
        break;
    default:
        return 'Операция не поддерживается';
}

return $expression . $result;
ivashkevich

isset возвращает true или false, не имеет смысла запихивать его внутрь empty().
В остальном - отлично!

demyanovpaul@yandex.ru

Его использовал, чтобы интерпретатор обрабатывал как 0. А он определял, то ли как null, то ли еще как то. Оттолкнулся от того, что isset() проверяет на существование переменной и после этого нули уже отрабатываются, исходя из этих соображений использовал.

virtual2018
<?php
if (empty($_GET)) {
    return 'Ничего не передано!';
}

if (empty($_GET['operation'])) {
    return 'Не передана операция';
}

if (!key_exists('x1', $_GET) || !key_exists('x2', $_GET)) {
    return 'Отсутсвуют аргументы';
}

if (!is_numeric($_GET['x1']) || !is_numeric($_GET['x2'])) {
    return 'Аргументы не могут быть строками';
}

$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';

switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '*':
        $result = $x1 * $x2;
        break;
    case '/':
        if ($x2 == 0) {
            return 'Ошибка деление на ноль';
        }
        $result = $x1 / $x2;
        break;
    default:
        return 'Операция не поддерживается';
}

return $expression . $result;
ivashkevich
if (!is_numeric($_GET['x1']) || !is_numeric($_GET['x2'])) {
    return 'Аргументы не могут быть строками';
}

Не совсем корректное сообщение. Скорее так - "Аргументы должны быть числами".

Bogdan
<?php
$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

 if ($x1 === '' || $x2 === '') {   //1.Дополните код так, чтобы можно было передавать 0.
    return 'Не переданы аргументы';
}else if ($x2 == '0' && $_GET['operation'] == '/') {  //3.Что произойдёт, если поделить на ноль? Добавьте обработку такой ситуации.
    return 'На 0 делить нельзя';
}else if (!is_numeric($x1) || !is_numeric($x2)) {  //4. Сделайте так, чтобы в качестве аргументов можно было отправить только числа.
    return "Введите числа";
}

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';
switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '/':   //2.Усовершенствуйте калькулятор так, чтобы он умножал и делил.
        $result = $x1 / $x2;
        break;
    case '*':   //2.Усовершенствуйте калькулятор так, чтобы он умножал и делил.
        $result = $x1 * $x2;
        break;
    default:
        return 'Операция не поддерживается';
}

return $expression . $result;
Bogdan

вот что вышло после оптимизации

<?php
$x1 = $_GET['x1'];
$x2 = $_GET['x2'];

if (!is_numeric($x1) || !is_numeric($x2)) {  //4. Сделайте так, чтобы в качестве аргументов можно было отправить только числа.
    return "Введите числа";
}

$expression = $x1 . ' ' . $_GET['operation'] . ' ' . $x2 . ' = ';
switch ($_GET['operation']) {
    case '+':
        $result = $x1 + $x2;
        break;
    case '-':
        $result = $x1 - $x2;
        break;
    case '/':   //2.Усовершенствуйте калькулятор так, чтобы он умножал и делил.
        if ($x2 == '0'){
            return 'На 0 делить нельзя';
        }
        $result = $x1 / $x2;
        break;
    case '*':   //2.Усовершенствуйте калькулятор так, чтобы он умножал и делил.
        $result = $x1 * $x2;
        break;
    default:
        return 'Операция не поддерживается';
}

return $expression . $result;
ivashkevich

Другое дело. Не надо торопиться и скидывать первое, что пришло в голову) Еще стоить проверять с помощью isset, что переменные вообще пришли.

Популярное за сутки
Сейчас читают
Логические задачи с собеседований