Diskuze: OOP Kalkulačka výstup
V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.


Kod mas spravne, pouze si vykladas spatne, jak funguje.
--- toto tam mas ---
<form method="POSt">
<select name="operace">
<option value="scitani">Sčítání</option>
<option value="odcitani">Odčítání</option>
<option value="nasobeni">Násobení</option>
<option value="deleni">Dělení</option>
</select>
--- pokud zvolis scitani, tak je to totez jako mit kod ---
<form method="POST">
<input type=hidden name=operace value=scitani>
--- php to prebira jako ---
$_POST['operace'] = 'scitani'
--- v php to v construct ukladas jako $operace = 'scitani'
public function __construct($prvniCislo, $druheCislo, $operace)
...
$this->operace = $operace; // $this->operace = 'scitani'
--- dale to v php porovnavas ---
$this->operace == 'scitani'
--- po sem je to ok, ze? ---
--- a take pomoci php z class vypisujes ---
echo "...". mb_strtoupper($kalkulacka->operace) // $this->operace == 'scitani' je stale bez diakritiky
// takze se to vypise jak? take bez diakritiky?
// takze bys tam musel pridat translator operaci na text s diakritikou, treba pomoci pole a isset()
+20 Zkušeností
+2,50 Kč

Lukáš Havlíček:25.1.2022 15:54
Ahoj, děkuji moc za radu. Dlouho jsem přemýšlel, jak to udělat s polem a pak jsem si vzpoměl na jeden úkol z klasického PHP. Teď můj kód vypadá takto a všechno funguje.
index.php
<!DOCTYPE html>
<html lang="cs-cz">
<head>
<meta charset="utf-8" />
<meta name="description" content="" /> <!-- Popis stránky -->
<meta name="keywords" content="" /> <!-- Klíčová slova -->
<meta name="author" content="" /> <!-- Autor webu -->
<link rel="shortcut icon" href="obrazky/ikona.ico" />
<link rel="stylesheet" href="styl.css" type="text/css" />
<title>Kalkulačka</title>
</head>
<body>
<h1 style="text-align: center">PHP objektově orientovaná kalkulačka</h1>
<form method="POSt">
<table border="1">
<tr>
<td>První číslo: </td>
<td><input name="prvniCislo" type="text" /> </td>
</tr>
<tr>
<td>Druhé číslo: </td>
<td><input name="druheCislo" type="text" /> </td>
</tr>
<tr>
<td>Operace: </td>
<td>
<select name="operace">
<option value="scitani">Sčítání</option>
<option value="odcitani">Odčítání</option>
<option value="nasobeni">Násobení</option>
<option value="deleni">Dělení</option>
</select>
</td>
</tr>
</table>
<input type="submit" value="Zjistit výsledek" />
</form>
<?php
mb_internal_encoding("UTF-8");
require_once ('tridy/Kalkulacka.php');
if ($_POST)
{
$kalkulacka = new Kalkulacka($_POST['prvniCislo'], $_POST['druheCislo'], $_POST['operace']);
echo('Zvolil jsi operaci: <strong>' . $kalkulacka->prevodOperace() . '</strong>.<br />');
echo('Výsledek této operace je: <strong>' . $kalkulacka->vypocitej() . '</strong>');
}
?>
</body>
</html>
Třída Kalkulacka.php
?php
class Kalkulacka
{
public $prvniCislo;
public $druheCislo;
public $operaceDiakritika = array (
'scitani' => 'SČÍTÁNÍ',
'odcitani' => 'ODČÍTÁNÍ',
'nasobeni' => 'NÁSOBENÍ',
'deleni' => 'DĚLENÍ',
);
public $operace;
public $chyba = 'Nulou nelze dělit ty joudo!';
public function __construct($prvniCislo, $druheCislo, $operace)
{
$this->prvniCislo = $prvniCislo;
$this->druheCislo = $druheCislo;
$this->operace = $operace;
}
public function prevodOperace()
{
$operace = strtr($this->operace, $this->operaceDiakritika);
return $operace;
}
public function vypocitej()
{
if ($this->operace == 'scitani')
{
$vysledek = $this->prvniCislo + $this->druheCislo;
return $vysledek;
}
else if ($this->operace == 'odcitani')
{
$vysledek = $this->prvniCislo - $this->druheCislo;
return $vysledek;
}
else if ($this->operace == 'nasobeni')
{
$vysledek = $this->prvniCislo * $this->druheCislo;
return $vysledek;
}
else if ($this->operace == 'deleni')
{
if ($this->druheCislo != 0)
{
$vysledek = $this->prvniCislo / $this->druheCislo;
return $vysledek;
}
else
{
return $this->chyba;
}
}
}
}
Já vím že už je to uzavřené a že to vlastně nebylo cílem dotazu, ale přeci jen bych pro případné další čtenáře ten finální výsled trochu upravil, aby z toho ten smysl OOP byl vidět přeci jen trochu lépe. V žádném případě se nejedná o kritiku, nebo cokoliv negativního. Naopak jsem moc rád že se autor ptá a chce se posunul někam dál.
Co bych změnil a proč (budu se bavit jen o třídě Kalkulačka):
- Podle názvu by třída měla fungovat jako kalkulačka tudíž její instance by měla být nezávislá na vstupech od uživatele. Tedy odstranit konstruktor či si v něm připravit obsah proměnné $operaceDiakritika a $chyba.
- Ted jak je třída navržená tak by pro každou operaci musela být nová instance třídy a to přece nechceme.
- Tak jak je to napsáno teď tak by se třída měla spíše jmenovat něco jako Příklad. Protože instance reprezentuje jeden konkrétní příklad.
- Není vyřešený problém s nezadáním vstupu, či špatného vstupu (např text)
- Používají se proměnné (Atributy třídy) i když jde o konstantní věci - $operaceDiakritika, $chyba. Nehledě na to, že jsou public i když k ním z venku nepřistupujeme.
- Pokud s výsledkem dané operace není potřeba nic dalšího dělat tak můžeme požít return na přímo, bez zbytečného ukládání do proměnné.
Ten výsledný kód bych si představoval nějak takto (typy na vstupech funkci nepíšu aby to bylo nezávislé na verzi php):
Třída Kalkulacka.php
<?php
class Kalkulacka
{
const OPERACE_SCITANI = 0;
const OPERACE_ODCITANI = 1;
const OPERACE_NASOBENI = 2;
const OPERACE_DELENI = 3;
const HLASKA_NEZNAMA_OPERACE = 'NEZNÁMÁ OPERACE';
const PREKLADOVA_MAPA_OPERACI = [
self::OPERACE_SCITANI => 'SČÍTÁNÍ',
self::OPERACE_ODCITANI => 'ODČÍTÁNÍ',
self::OPERACE_NASOBENI => 'NÁSOBENÍ',
self::OPERACE_DELENI => 'DĚLENÍ',
];
/**
* @throws RuntimeException
*/
public function vypocitej($prvniCisloString, $druheCisloString, $operaceVstup)
{
$prvniCislo = $this->osetriVstupniCislo($prvniCisloString);
$druheCislo = $this->osetriVstupniCislo($druheCisloString);
$operace = $this->osetriOperaci($operaceVstup);
// použití swithce
switch ($operace) {
case self::OPERACE_SCITANI:
return $this->secti($prvniCislo, $druheCislo);
case self::OPERACE_ODCITANI:
return $this->odecti($prvniCislo, $druheCislo);
case self::OPERACE_NASOBENI:
return $this->nasob($prvniCislo, $druheCislo);
case self::OPERACE_DELENI:
return $this->vydel($prvniCislo, $druheCislo);
default:
throw new \RuntimeException("Byla zadaná neznámá operace: {$operace}");
}
// když se nelíbí switch tak můžeme třeba takto
if ($operace === self::OPERACE_SCITANI) {
return $this->secti($prvniCislo, $druheCislo);
}
if ($operace === self::OPERACE_ODCITANI) {
return $this->odecti($prvniCislo, $druheCislo);
}
if ($operace === self::OPERACE_NASOBENI) {
return $this->nasob($prvniCislo, $druheCislo);
}
if ($operace === self::OPERACE_DELENI) {
return $this->vydel($prvniCislo, $druheCislo);
}
throw new \RuntimeException("Byla zadaná neznámá operace: {$operace}");
//případně od php 8.0 můžem použít match
return match ($operace){
self::OPERACE_SCITANI => $this->secti($prvniCislo, $druheCislo),
self::OPERACE_ODCITANI => $this->odecti($prvniCislo, $druheCislo),
self::OPERACE_NASOBENI => $this->nasob($prvniCislo, $druheCislo),
self::OPERACE_DELENI => $this->vydel($prvniCislo, $druheCislo),
default => throw new \RuntimeException("Byla zadaná neznámá operace: {$operace}")
};
}
/**
* @throws RuntimeException
*/
private function osetriOperaci($operaceVstup)
{
if (is_int($operaceVstup) && $this->existujeOperaceVPrekladoveMape((int)$operaceVstup)) {
return (int)$operaceVstup;
}
throw new \RuntimeException("Byla zadaná neznámá operace: {$operaceVstup}");
}
public function prevedOperaciNaText($operace)
{
if ($this->existujeOperaceVPrekladoveMape($operace)) {
return self::PREKLADOVA_MAPA_OPERACI[$operace];
}
return self::HLASKA_NEZNAMA_OPERACE; // nebo lépe vyhodit Exception -> throw new \RuntimeException("Byla zadaná neznámá operace: {$operace}");
}
/**
* @throws RuntimeException
*/
private function osetriVstupniCislo($cisloVstup)
{
//tady může být x ruzných kontrol, třeba i pomocí regulárního výrazu atd.
if (is_float($cisloVstup)) {
return (float)$cisloVstup;
}
throw new RuntimeException("Zadaná hodnota: {$cisloVstup}, není číslo.");
}
private function existujeOperaceVPrekladoveMape($operace)
{
return array_key_exists($operace, self::PREKLADOVA_MAPA_OPERACI);
}
private function secti($prvniCislo, $druheCislo)
{
return $prvniCislo + $druheCislo;
}
private function odecti($prvniCislo, $druheCislo)
{
return $prvniCislo - $druheCislo;
}
private function nasob($prvniCislo, $druheCislo)
{
return $prvniCislo * $druheCislo;
}
/**
* @throws RuntimeException
*/
private function vydel($prvniCislo, $druheCislo)
{
if ($druheCislo === 0) {
throw new \RuntimeException('Nulou nelze dělit ty joudo!');
}
return $prvniCislo / $druheCislo;
}
}
A adekvátně upravíme i index.php, kde využijeme konstanty s operacemi.
<?php
mb_internal_encoding("UTF-8");
require_once('tridy/Kalkulacka.php');
?>
<!DOCTYPE html>
<html lang="cs-cz">
<head>
<meta charset="utf-8"/>
<meta name="description" content=""/> <!-- Popis stránky -->
<meta name="keywords" content=""/> <!-- Klíčová slova -->
<meta name="author" content=""/> <!-- Autor webu -->
<link rel="shortcut icon" href="obrazky/ikona.ico"/>
<link rel="stylesheet" href="styl.css" type="text/css"/>
<title>Kalkulačka</title>
</head>
<body>
<h1 style="text-align: center">PHP objektově orientovaná kalkulačka</h1>
<form method="POST">
<table border="1">
<tr>
<td>První číslo:</td>
<td><input name="prvniCislo" type="text"/></td>
</tr>
<tr>
<td>Druhé číslo:</td>
<td><input name="druheCislo" type="text"/></td>
</tr>
<tr>
<td>Operace:</td>
<td>
<select name="operace">
<option value="<?= Kalkulacka::OPERACE_SCITANI ?>">Sčítání</option>
<option value="<?= Kalkulacka::OPERACE_ODCITANI ?>">Odčítání</option>
<option value="<?= Kalkulacka::OPERACE_NASOBENI ?>">Násobení</option>
<option value="<?= Kalkulacka::OPERACE_DELENI ?>">Dělení</option>
</select>
</td>
</tr>
</table>
<input type="submit" value="Zjistit výsledek"/>
</form>
<?php
if (isset($_POST['prvniCislo'], $_POST['druheCislo'], $_POST['operace'])) {
$kalkulacka = new Kalkulacka();
$operaceText = $kalkulacka->prevedOperaciNaText($_POST['operace']);
$operaceVyslednyText = "Zvolil jsi operaci: <strong>{$operaceText}</strong>.";
try {
$vysledek = $kalkulacka->vypocitej($_POST['prvniCislo'], $_POST['druheCislo'], $_POST['operace']);
$vysledekText = "Výsledek této operace je: <strong>{$vysledek}</strong>";
} catch (RuntimeException $e) {
$vysledekText = "Při výpočtu došlo k chybě: {$e->getMessage()}";
}
echo $operaceVyslednyText;
echo '<br>';
echo $vysledekText;
}
?>
</body>
</html>
Zobrazeno 4 zpráv z 4.