Шаг 3 - Как сделать калькулятор

Пришло ко мне письмо с просьбой поменяться линками между сайтами от создателей www.progteam.ru. Сайт новый и поэтому не раскрученный, но задачи, которые они перед собой ставят весьма сильные. Из того, что меня сразу заинтересовало на этом сайте это раздел про PHP, куда я зашел практически машинально.

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

Автор данного урока, некий Stalk, в качестве примера программы на PHP приводит пример реализации калькулятора, чтобы было доступно и просто для начинающих. Я приведу Вам весь его код, надеюсь не сочтут за плагиат... На случай, если этот материал исчезнет из сети.

<html> 
 <head> 
  <title>Калькулятор</title> 
 </head> 
 <body> 

 <? 
  $a=$_GET['action']; //Для удобства переписываем значения полей присланной формы в простые переменные. 
  $x=$_GET['x']; 
  $y=$_GET['y']; 
  $result=0; //Это переменная для результата действия 
  if($a=="+") //Проверяем значения переменной $a - действие, которое мы должны выполнить 
          //сложение 
   $result=$x+$y; 
  else if($a=="-") //вычитание 
   $result=$x-$y; 
  else if($a=="*") //умножение 
   $result=$x*$y; 
  else if($a=="/" //деление 
          && $y!=0) //на 0 делить нельзя 
   $result=$x/$y; 
  else if($a=="^"){ //возведение в степень 
   $result=1; //Его мы будем умножать, значит начальное значение 1. 
   for($i=0;$i<$y;$i++) //Об этом ниже, в пояснении 
    $result*=$x; 
  } 

  else 
   $result="Действие не выбрано"; //Мы не узнали ни одного действия 

  //Теперь выводим результат 
  echo "x"; 
  if($a) 
   echo $a; //Если действие выбрано - между переменными показываем это действие 
  else 
   echo " "; //Иначе покажем пробел 
  echo "y=$result<br/>"; //х у=чему-то... И еще надо бы не забыть отступить строчку до начала формы 
 ?> 

  <form action="calculator.php" method=get> 
   Введите х: <input type=text name=x><br/> 
   Введите у: <input type=text name=y><br/> 
   Выберите действие: 
   <select name=action> 
    <option value="+">х+у</option> 
    <option value="-">х-у</option> 
    <option value="*">х*у</option> 
    <option value="/">х/у</option> 
    <option value="^">х^у</option> 
   </select><br/> 
   <input type=submit value="Считай"> 
  </form> 
 </body> 
</html>

Если Вы заметили, то автор использует для вставки кода <? ?>, даже не знаю к чему бы это. Попробуем добавить к этой программе, тот код который мы мучительно создавали в предыдущих шагах. Добавьте его в самое начало файла.

<?php
/*foreach ($_REQUEST as $name => $value) {
	eval("unset(\$".$name.");");
};*/
foreach($_REQUEST as $key => $val) {
	if(isset($$key)) unset($$key);
};
if (get_magic_quotes_gpc()) {
$_GET = array_map('stripslashes', $_GET);
$_POST = array_map('stripslashes', $_POST);
$_COOKIE = array_map('stripslashes', $_COOKIE);
};
ini_set("magic_quotes_gpc","0");
ini_set("magic_quotes_runtime","0");
ini_set("display_errors","1");
if (version_compare(phpversion(), "5.0.0", ">")==1) {
ini_set("error_reporting", E_ALL | E_STRICT);
} else {
ini_set("error_reporting", E_ALL);
};
?>

Первый же вызов дает результат...

Notice: Undefined index: action in /home/www.firststeps.ru/2.php on line 24

Notice: Undefined index: x in /home/www.firststeps.ru/2.php on line 25

Notice: Undefined index: y in /home/www.firststeps.ru/2.php on line 26

Так как вам это ?! Именно от этого я пытаюсь Вас уберечь. Научившись делать все правильно сразу, Вы никогда не сможете сделать ошибку, потому что просто напросто не будете знать как ее сделать :)

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

if (isset($_REQUEST["action"])) {
	$a=$_REQUEST["action"];
} else {
	$a="";
};

Я специально отошел от оригинала и заменил $_GET на $_REQUEST, по причинам, которые я уже объяснял раньше. Теперь, если параметр action существует, то запоминаем его в переменной $a. Если же его нет, то вероятнее всего разумным будет сделать переменную $a пустой строкой, чтобы дальнейшая работа с ней не могла привести к каким-то непредвиденным результатам. Дальше я бы на месте автора проанализировал эту переменную и решил бы, что делать дальше...

if ($a!="") {
	// тут код калькулятора
};

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

С получением параметров x и y получается веселее. Запомните, все что Вам передал пользователь Вы должны проверить на соответствие нужному типу данных, или привести эти данные к нужному типу. Я предполагаю, что числа над которыми ведется работа должны быть вещественными, поэтому делаем так как нам нужно:

if (isset($_REQUEST["x"])){
	$x=(float)$_REQUEST["x"]; 
} else {
	$x=0;
};

if (isset($_REQUEST["y"])){
	$y=(float)$_REQUEST["y"]; 
} else {
	$y=0;
};

Т.е. параметры x и y мы насильно загоняем в формат вещественного числа явным переопределением типа. Теперь, если кто-то захочет скормить калькулятору фразу вася + маша, то в ответ получит нуль :), так как преобразование из текста в вещественное число отбросит все неверные символы.

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

switch ($a) {
	case "+": $result = $x + $y; break;
	case "-": $result = $x - $y; break;
	case "*": $result = $x * $y; break;
	case "/": if ($y != 0) {
			$result = $x / $y;
		} else { 
			$result = "деление на ноль";
		};
		break;
	case "^": $result = 1;
		for ($i=0; $i < $y; $i++) {
			$result *= $x;
		};
		break;
	default: $result = "Неизвестное действие";
};

Таким образом мы разобрались с тем, как надо правильно получать данные от пользователя. Я каждый раз Вам буду напоминать об этом, пока Вас не станет тошнить от этого :) Доведите это дело до автоматизма, тогда Вы будете защищены от всех напастей.

Я конечно хочу преклониться перед авторами этого сайта, так как знаю, что такое написать обучающую статью. Несомненно для каждой такой статьи найдется кучка цинников-критиканов, которые разобьют все старания в пух и прах. Прошу прошения, что сам стал таким, но это лишь ради Вас и ради искусства. Теперь Вы можете и меня покритиковать... Авось доведем дело до совершенства...


Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Кузин Андрей - 17.10.2005