5. díl - Práce s MySQL v PHP - PDO objektově a modulárně

PHP Ostatní Práce s MySQL v PHP - PDO objektově a modulárně

V předchozím článku http://www.itnetwork.cz/…ovladace-pdo jsem napsal, že by bylo vhodné oddělit práci s databází do samostatné třídy, abychom s ní mohli pracovat na více místech - nejen ve třídě Adresar a nemuseli ji pokaždé znovu otevírat. Otevírání databáze je totiž časově náročná operace. Proto ji v aplikaci otevřeme jen jednou a použijeme všude, kde se nám bude hodit.

Tentokrát již bude jméno třídy MyDB na místě. Vytvořil jsem vlastní jednoduchou nadstavbu databáze.

<?php
// soubor MyDB.class.php

class MyDB{
  private $spojeni;

  function __construct($host,$user,$pass,$name){
    $options=array(
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
      PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
      );
    $this->spojeni= @new PDO("mysql:host=$host;dbname=$name",$user,$pass,$options);
  }

  function query($query,$param=Array()){
      $navrat=$this->spojeni->prepare($query);
      $navrat->execute($param);
      return $navrat->rowCount();
  }

  function queryOne($query,$param=Array()){
      $navrat=$this->spojeni->prepare($query);
      $navrat->execute($param);
      return $navrat->fetch(PDO::FETCH_ASSOC);
  }

  function queryAll($query,$param=Array()){
      $navrat=$this->spojeni->prepare($query);
      $navrat->execute($param);
      return $navrat->fetchAll(PDO::FETCH_ASSOC);
  }
}

Jak je vidět, kromě otevření databáze jsem si vyrobil 3 metody:

  • query(), která vrací jen počet ovlivněných řádek v DB
  • queryOne(), která vrací první záznam, na který narazí
  • queryAll(), která vrací kompletní výsledek dotazu

V mé aplikaci sice budu potřebovat jen jednu z nich, ale ty zbývající se nám jistě budou hodit v některém z dalších pokračování tohoto seriálu. Pokud by někomu nějaká metoda chyběla, může si ji dopsat. Chybí zde například iterátor pro vybírání výsledků dotazu. Pokud však nepotřebujeme získávat z tabulky statisíce řádek, chybět nám nebude.

Prvním parametrem je SQL dotaz. Druhý parametr je nepovinný a slouží k předávání dat pomocí tzv. parametrizovaných dotazů. Je to vynikající vlastnost ovladačů MySQLi a PDO. Původní ovladač tuto vlastnost nemá, proto je nutné data od uživatelů ošetřit funkcí mysql_real_escape_string(). PDO tuto berličku nepotřebuje, data je možné předávat přímo. Nespornou výhodou je, že délka vkládaných dat se nezapočítává do limitu délky SQL dotazu. To jistě ocení zejména ti, kteří rádi do databáze ukládají fotky či videa. V našem příkladu druhý parametr zatím nebude použit.

<?php
// soubor Adresar.class.php

class Adresar{
  private $seznam;

  function __construct($spojeni){
    $this->seznam=$spojeni->queryAll("SELECT * FROM adresar");
    if(!sizeof($this->seznam)) {
      throw new Exception("Tabulka je prázdná");
    }
  }

  function __toString() {
    $headers='<tr><th>'.implode('</th><th>',array_keys($this->seznam[0])).'</th></tr>';
    $rows=array();
    foreach($this->seznam as $row){
      $rows[]='<tr><td>'.implode('</td><td>',array_map('htmlspecialchars',$row)).'</td></tr>';
    }
    $table=implode("\n",$rows);
    return <<<EOT
<table border="1">
$headers
$table
</table>

EOT;
  }
}

Třída Adresar doznala jen kosmetické změny. Zjednodušil se konstruktor a volání SQL dotazu. Presenter je stále stejný.

Zbývá už jen hlavní modul, který nazvu jednoduše index.php. Musím mu nějak vysvětlit, aby si natáhl potřebné moduly a pracoval s nimi. K tomu slouží příkaz include():

include('MyDB.class.php');
include('Adresar.class.php');

Jenže dnes už se to tak nedělá, protože u větších projektů by mohlo být dost pracné a nepřehledné starat se o natažení všech modulů. Naštěstí si můžeme v PHP nadefinovat funkci se speciálním názvem __autoload(), která to udělá za nás pokaždé, když budeme chtít nějakou třídu použít.

<?php
// soubor index.php

function __autoload($class){
  include($class.'.class.php');
}

try{
  $spojeni=new MyDB("localhost","kit","","test");
  $adresar=new Adresar($spojeni);
  echo $adresar;
} catch(Exception $e) {
  echo "Tabulku nelze vypsat<br />\n";
  echo $e->getMessage(),"\n";
}

Nyní je již aplikace hotova. Je sice trochu delší, než byla původně, ale získali jsme modulárnost. Databázi můžeme použít i pro jiný účel se zjednodušeným ovládáním. Třídě Adresář můžeme podstrčit jinou databázi nebo jiný zdroj dat. Pokud budeme potřebovat jinou vlastnost databáze, prostě ji do třídy přidáme jako další metodu.

Jeví se někomu výsledný kód příliš komplikovaný? I to je možné. Úplně první příklad dělal prakticky to samé a měl jen 14 řádek. Jenže vypsání tabulky je velmi primitivní úloha. U běžných aplikací bychom velmi rychle ztratili přehled a zhoršila by se udržovatelnost kódu.

Příště si uděláme trochu složitější příklad a vysvětlíme si záhadnou zkratku CRUD.


 

  Aktivity (2)

Článek pro vás napsal Kit
Avatar
Jsem spokojeným uživatelem operačních systémů založených na linuxovém jádře. Zejména openSUSE a Ubuntu. Pro psaní veškerých textů a programů používám vynikající textový editor Vim. Aplikace se snažím psát vždy v tom nejvhodnějším programovacím jazyk...

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


 


Miniatura
Všechny články v sekci
Ostatní tutoriály v PHP

 

 

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

Avatar
Kit
Redaktor
Avatar
Kit:

Na WZ je stále nejnovější PHP 5.2.13 a využívá ho dost začátečníků. Dokud nepotřebuji za běhu měnit způsob natahování modulů, vystačím si s __autoload(). Klidně si můžeš za něj připsat

spl_autoload_register('__autoload');

Až se dostaneme k anonymním funkcím, tak už to bez PHP >= 5.3 nepůjde.

Odpovědět 7.7.2012 11:53
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Kit:

Proto jsem z WZ utekl na Endoru, kde je PHP 5.3.13. Je tam i rychlejší MySQL, ale občas mi zmizí a musím ji založit znovu. Raději používám SQLite.

Odpovědět 7.7.2012 12:05
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Karel
Neregistrovaný
Avatar
Karel:

Sem ještě docela začátečník a chci se zeptat jak stímhle můžu dál pracovat?

 
Odpovědět 10.3.2013 23:46
Avatar
Odpovídá na Kit
Luboš Běhounek (Satik):

Na Endoře mám jeden web asi 3 roky a bez problémů, DB se mi ještě neztratila.. :)

Odpovědět 10.3.2013 23:54
:)
Avatar
Kit
Redaktor
Avatar
Odpovídá na Luboš Běhounek (Satik)
Kit:

Možná jsem si to spletl s IC. Možná mi ta databáze expirovala pro nečinnost.

Odpovědět 11.3.2013 9:48
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
mkub
Redaktor
Avatar
mkub:

v tvojom priklade sa 3x opakuje tento kod:

$navrat=$this->spojeni->prepare($query);
$navrat->execute($param);

myslim, ze by sa dal nahradit privatnou metodou a tam kde sa ma pouzit, tak sa na tu metodu jednoducho odkazovat pomocou $this
tym by sa skratil cely kod triedy

 
Odpovědět 17.11.2013 14:52
Avatar
Kit
Redaktor
Avatar
Odpovídá na mkub
Kit:

Kód třídy by se tím prodloužil. Proto je to tak jak to je.

Odpovědět 17.11.2013 14:57
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
mkub
Redaktor
Avatar
Odpovídá na Kit
mkub:

myslim, ze v tomto pripade mierne, ale pri vacsom mnozstve metod definicia privatnej metody by zmensil kod triedy
ja mam radsej, ked sa opakujuci kod zapise iba raz a potom sa nan na potrebnom mieste odkazuje

 
Odpovědět 17.11.2013 15:07
Avatar
Kit
Redaktor
Avatar
Odpovídá na mkub
Kit:

Ten kód se mi většinou neopakuje tak jak v tomto příkladu. Nepotřebné metody tam nedávám a naopak tam dávám komplexnější, které některé parametry doplňují samy z lokálních atributů a konstant. Databázovou vrstvu prostě nedělám tak primitivní jako v tomto příkladu.

Dnes bych to napsal jinak, ale přepisovat to nebudu a opravovat už vůbec ne.

Snažím se, aby se mi celá třída vešla do 60 řádek, takže o moc delší je stejně nedělám.

Editováno 17.11.2013 15:22
Odpovědět 17.11.2013 15:21
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Ondřej Langr (andysekcze):

Kde je ten další díl? :D

Odpovědět 1.10.2015 13:58
I have a charger. I have Note 7. Umh I haven't Note7.
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 14. Zobrazit vše