1. díl - Tipy pro začátečníky v PHP

PHP Tipy pro začátečníky Tipy pro začátečníky v PHP

Vítám vás u prvního článku série Tipy pro začátečníky v PHP. Ukáži vám několik příkladů, kde je kódu zbytečně navíc a které by se mohly zapsat lépe, jednodušeji a v některých případech by se i (byť jen minimálně) zlepšil výkon.

Ukáži vám špatné příklady a pokud bude třeba, tak se pokusím i o řešení, za které byste se nemuseli stydět. Možná si někteří z vás i zavzpomínají na své vlastní začátky při programování a některým to může pomoci zbavit se zbytečného kódu. Děkuji za přečtení a ať se články líbí!

Začneme úplně jednoduchými příklady, které se v praxi nikde nevyskytují. No, možná byste se divili...

Nevhodné názvy proměnných

a) Nicneříkající název

Většinou je jednodušší napsat nějaký náhodný název proměnné, aby se vymýšlením názvů nezabil čas. Jedná se například o takovéto případy:

1: $aaa = 10;
2: $x1 = array("a", "b");
3: $x2 = array("c", "d");
4: $x163 = "nějaký řetězec";

Proč vymýšlet nějaké názvy, když to stejně jednou někde použiji a nebudu to více řešit? Problém nastává ve chvíli, kdy budete dělat větší script, takže si poté budete říkat:

6336: if ($x163 !== fooBar()) {
6337:    // co že je to $x163 ?!
6338:    ...
6339: }

Navíc chudáci kolegové, pokud něco takového uvidí ve společném projektu.

b) Míchání jazyků

Jedná se o případ, kdy v názvu použijete například češtinu a angličtinu.

$numberOfLidi
$pocetCars

Nejedná se pouze o konkrétní proměnnou, ale v celém projektu by se měl používat jeden jazyk, a to včetně názvů funkcí apod. V opačném případě vzniknou takovéto kusy kódu:

if (count($inputData) > $naseSuperKonfigurace["dataStorage"]["maximalnyPocetZaznamov"]) {
  ...
}

Obvykle je dobré psát celý program v angličtině. Jednak jsou anglicky i klíčová slova PHP, takže pokud byste chtěli program zveřejnit třeba jako open-source, ostatní vývojáři mu lépe porozumí.

c) Špatně zvolený název

Další špatná situace může nastat v případě, že použijete špatný název. Pro ukázku to přeženu:

$karluvVek = array(-4, 10, "abc");

Je sice hezké, že jste zvolili určitý název a dokonce i v jednom jazyce, ale pod názvem karlův věk asi nebudete očekávat pole se třemi různými hodnotami (a ještě k tomu jednou zápornou a třetí řetězcem).

Výjimku tvoří například proměnné $i a $j, které se používají při iteraci (např. procházení pole).

Použití mnoha podmínek elseif

Tento případ je někdy vidět například při tvorbě dynamických stránek, kdy je název přenášen přes parametr v URL.

$page = $_GET["page"];

if ($page === "home") {
  include "home.php;"
} elseif ($page === "about") {
  include "about.php";
} elseif ($page === "contact") {
  include "contact.php";
} elseif ($page === "sitemap") {
  include "sitemap.php";
} /* atd ... */ else {
  include "404.php";
}

Kromě toho, že to je dost nepřehledné (představte si třeba 100 různých stránek), tak zabijete hromadu řádků a ještě kdybyste náhodou chtěli změnit název proměnné $page, budete hezky přepisovat všechny podmínky.

Řešit se to dá velmi jednoduše, když si vytvoříte whitelist, neboli seznam povolených hodnot:

$page = $_GET["page"];
$allowedPages = array("home", "about", "contact", "sitemap");

if (isset($allowedPages[$page])) {
  $file = "{$page}.php";
  include $file;
} else {
  include "404.php";
}

Pole se dá navíc jednoduše rozšířit. Například pokud budete chtít mít jiný název souboru, můžete si udělat asociativní pole:

$page = $_GET["page"];
$pages = array(
  "home" => "home.php",
  "about" => "aboutMe.php",
  ...
);

if (isset($pages[$page])) {
  include $pages[$page];
} else {
  include "404.php";
}

Pole můžeme rozšířit o další prvky, které se využijí na každé stránce.

<?php

$page = $_GET["page"];  // budeme předpokládat, že parametr page v URL vždy existuje

$pages = array(
  "home" => array(
    "file" => "home.php",
    "title" => "Domů",
    "needLogin" => FALSE
  ),

  "admin" => array(
    "file" => "admin/index.php",
    "title" => "Administrace",
    "needLogin" => TRUE
  ),

  "404" => array(
    "file" => "404.php",
    "title" => "Chyba 404, stránka nenalezena"
  ),

  "onlyForLoggedUsers" => array(
    "file" => "onlyForLoggedUsers.php",
    "title" => "Pouze pro přihlášené"
  )
);

if (isset($pages[$page])) {
  $pageData = $pages[$page];

  if (isset($pageData["needLogin"]) && $pageData["needLogin"]) {

    // pokud stránka vyžaduje přihlášení, automaticky se provede kontrola
    if (!isset($_SESSION["userId"])) {
      $pageData = $pages["onlyForLoggedUsers"];
    }
  }
} else {
  $pageData = $pages["404"];
}

?>
<html>
  <head>
    <meta charset="UTF-8" />
    <title><?php $pageData["title"]; ?></title>
  </head>
  <body>

  <?php

  include $pageData["file"];

  ?>

  </body>
</html>

Tento příklad může fungovat pro malé a velmi jednoduché weby. Pokud budete chtít přidávat různá zpracování formulářů, je lepší ten kód sestavit trochu jinak (protože by zpracování formuláře mělo proběhnout ještě před jakýmkoliv výpisem HTML).

Přepisování hodnot pole

Pokud budete potřebovat z nějakého důvodu změnit hodnoty v nějakém poli, můžete to vyřešit takovýmto způsobem:

$numbers = array(1, 2, 3, 4, 5);
$count = count($numbers);
for ($i = 0; $i < $count; $i++) {
  $numbers[$i] = $numbers[$i] * 2;
}

Řádek s násobením lze pomocí reference (odkaz na proměnnou) zjednodušit:

foreach ($numbers as &$number) {
  $number = $number * 2;
}

Všimněte si znaku & (ampersand) před proměnnou $number. Pomocí něj se nezkopíruje obsah daného prvku, ale uloží se odkaz na místo v paměti. Znamená to, že pokud upravíme hodnotu proměnné $number, tak se změní hodnota i daného prvku v poli.

Příliš velké větvení

Velké zanořování podmínek lze vidět například u zpracování formulářů. Jednoduchý příklad, který by mohl znázornit registraci uživatele:

if ($_POST) {
  if (!empty($_POST["name"])) {
    if (empty($_POST["pass"])) {
      if (empty($_POST["repass"])) {
        if (!empty($_POST["email"])) {
          if ($_POST["pass"] === $_POST["repass"]) {
            if (strlen($_POST["name"]) > 5) {
              // dokončení registrace
            } else {
              echo "Jméno obsahuje málo znaků";
            }
          } else {
            echo "Hesla se neshodují";
          }
        } else {
          echo "Nebyl zadán e-mail"
        }
      } else {
        echo "Nebylo zadáno kontrolní heslo";
      }
    } else {
      echo "Nebylo zadáno heslo";
    }
  } else {
    echo "Nebylo zadáno jméno";
  }
}

// a to jsem tam nepřidal kontrolu mailu, znaků ve jméně a hromadu dalších potenciálních podmínek

Zbavit se tohoto nepřehledného kódu je velmi snadné. Tento způsob nám dokonce umožní uložit více chyb, takže není nutné uživatele pokaždé otravovat s jednou hláškou do doby, než se rozhodne stránku zavřít.

$errors = array();
if ($_POST) {
  if (empty($_POST["name"])) {
    $errors[] = "Nebylo vyplněno jméno";
  }
  if (empty($_POST["pass"])) {
    $errors[] = "Nebylo vyplněno heslo";
  }
  if (empty($_POST["repass"])) {
    $errors[] = "Nebylo vyplněno kontrolní heslo";
  }
  if (empty($_POST["email"])) {
    $errors[] = "Nebyl vyplněno e-mail";
  }

  if (empty($errors)) {  // pokud zatím nejsou žádné chyby, můžeme pokračovat dále
    if (strlen($_POST["name"]) <= 5) {
      $errors[] = "Jméno obsahuje příliš málo znaků";
    }
    if ($_POST["pass"] !== $_POST["repass"]) {
      $errors[] = "Zadaná hesla se neshodují";
    }

    if (empty($errors)) {
      // dokončení registrace
    }
  }
}

Vypsat jednotlivé chyby poté můžete jednoduše pomocí cyklu.

if (!empty($errors)) {
  echo "<ul>";
  foreach ($errors as $error) {
    echo "<li>{$error}</li>";
  }
  echo "</ul>";
}

Řešení samozřejmě také obsahuje určité zanořování, ale kód se najednou zdá mnohem přehlednější. V podstatě jde o sérii určitých podmínek, kde se na konci zjišťuje stav (jsou chyby/nejsou chyby). Je to proto, aby se při nevyplnění jména nezobrazila jak hláška "nevyplněné jméno", tak i zároveň "jméno obsahuje málo znaků".

Počítání prvků v poli během cyklu

Často je v kódu vidět, že se používá funkce count nebo sizeof (obě dělají to samé), když se prochází nějaké pole.

for ($i = 0; $i < count($fields); $i++) {
  // nějaký kód
}

Při procházení cyklem se pokaždé testuje podmínka. Znamená to, že se pokaždé zavolá funkce count(), aby prvky v poli spočítala. Chyba to není, jen se to pokaždé zbytečně počítá znovu. Možná by to bylo znát na výkonu, kdyby to pole obsahovalo třeba milion hodnot. Řešením je spočítat prvky před cyklem a do podmínky dosazovat pouze proměnnou.

$fieldsCount = count($fields);
for ($i = 0; $i < $fieldsCount; $i++) {
  // nějaký kód
}

To je z prvního článku vše. Děkuji za přečtení a pokud bude zájem, rád se toho pokusím sepsat více (například zbytečnosti při práci s daty z databáze atp.).


 

  Aktivity (1)

Článek pro vás napsal Martin Konečný (pavelco1998)
Avatar
Autor se o IT moc nezajímá, raději by se věnoval speciálním jednotkám jako jsou SEALs nebo SAS. Když už to ale musí být něco z IT, tak tvorba web. aplikací v PHP.

Jak se ti líbí článek?
Celkem (27 hlasů) :
4.962964.962964.962964.962964.96296


 


Miniatura
Všechny články v sekci
Tipy pro začátečníky v PHP
Miniatura
Následující článek
Tipy pro začátečníky v PHP

 

 

Komentáře
Zobrazit starší komentáře (1)

Avatar
Daniel Vítek
Tým ITnetwork
Avatar
Daniel Vítek:

(tím jsem chtěl zdůraznit, že psát miliony ifů je blbost a hrozně dlouhý :) )

 
Odpovědět  ±0 21.1.2015 12:23
Avatar
Martin Konečný (pavelco1998):

Díky. No s těmi ify byla práce a to jsem je ještě ušetřil :D
V některých případech se ale většímu počtu ifů vyhnout nejde, proto je dobrý se alespoň pokusit udělat to přehledně :)

 
Odpovědět  +3 21.1.2015 12:47
Avatar
IT Man
Redaktor
Avatar
IT Man:

Mohl bys napsat i nějaký článek s komentáři, protože někteří nováčci do svých programů si nedávají komentáře. Za pár měsíců to však poznaj a nepoznají, jaká metoda co dělá. :)

Odpovědět  +1 22.1.2015 10:53
Když nevíš jak dál, podá ti ruku někdo, od koho by jsi to nečekal. A tu šanci musíš přijmout!
Avatar
Odpovídá na IT Man
Martin Konečný (pavelco1998):

Jestli máš na mysli správné použití komentářů, tak to můžu hodit do dalšího dílu :)

 
Odpovědět  +4 22.1.2015 11:46
Avatar
Marek Z.
Redaktor
Avatar
Marek Z.:

Ach to větvení.. :`

Odpovědět  +1 22.1.2015 14:10
Chybami se člověk učí, běžte se učit jinam!
Avatar
Pavel Vosyka
Člen
Avatar
Pavel Vosyka:

No white list mě nikdy předtím nenapadl. Záleží na konkrétním případu.. ale místo těch ifů používám switch :-)

Odpovědět 29.1.2015 22:59
"nikdy nepiš nic 2x"
Avatar
Odpovídá na Pavel Vosyka
Martin Konečný (pavelco1998):

Samozřejmě neexistuje jeden univerzální postup, který je nejlepší pro všechny případy.
Switch je lepší než ify, pokud ty akce nejsou dlouhé (např. do třech řádků). I přesto je whitelist ušetřením řádků i v porovnání se switchem.

 
Odpovědět 29.1.2015 23:14
Avatar
Pavel Vosyka
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Pavel Vosyka:

No.. souhlasím s tím, že fakt záleží na konkrétní situaci.

Dělám teď jedny stránky - spíš galerii, kde se alba načítaj podle složek na serveru a jsou asi jen 3 stránky statický ("o mně", "kontakt", tak vlastně dvě) - v jiných případech se zjišťuje jestli existuje složka s tím názvem, jinak "error" stránka. Takže tady by byl whitelist asi zbytečnej :-)

Ale i tak je whitelist dobrý nápad, který mě předtím vůbec nenapadl :-)

Je fajn, že se takhle někdo dělí o svůj "framework" :-)

Odpovědět 29.1.2015 23:29
"nikdy nepiš nic 2x"
Avatar
Odpovídá na Pavel Vosyka
Martin Konečný (pavelco1998):

Na hodně problémů existuje více řešení, jde o to zvolit to správný :)
Jde o to, aby ti pak nevznikly zbytečně dlouhé řádky různých podmínek, když to v podstatě lze vyřešit jedním polem a jedinou podmínkou.
Naopak pokud bys například tahal údaje na stránkách z databáze, pak by to pole bylo zbytečné, protože bys zjistil už podle databázového dotazu, jestli daná stránka existuje (zda se podle dané URL adresy nalezne nějaký řádek).

 
Odpovědět  +1 29.1.2015 23:57
Avatar
Dominik Matoušek:

Skvěle napsané :)

 
Odpovědět 27. května 13:34
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 11. Zobrazit vše