4. díl - Práce s MySQL v PHP - Použití ovladače PDO

PHP Ostatní Práce s MySQL v PHP - Použití ovladače PDO

V předchozím dílu seriálu http://www.itnetwork.cz/…adace-mysqli jsme si ukázali, že objektové řešení přístupu k databázi je možná o něco delší, než procedurální, ale zato je o něco přehlednější a robustnější.

Databázový svět se neomezuje jen na databázi MySQL, ale použitelných databází je v něm několik desítek. Každá se ovládá trochu jinak a pro každou vznikl nový ovladač. Proto vývojáři přišli s myšlenkou vytvoření jednotného ovladače, který se z pohledu programátora bude chovat pokaždé stejně, bez ohledu na typ připojené databáze.

První pokusy dopadly fiaskem, protože vytvořit kompletní rozhraní pro všechny typy databází se ukázalo jako nemožné. Buď bylo primitivní a nedokázalo využít všech vlastností použité databáze, anebo byla jeho vnitřní struktura značně komplikovaná, aby emulovala nedostatky jiných databází.

Byl tedy vytvořen kompromis. Vcelku jednoduchá třída, která pro každou společnou vlastnost všech databází nabízí stejnou metodu ovládání. Některé metody jsou funkční jen pro některé databáze. Ukázalo se to jako velmi výhodné řešení nazvané

PHP Data Objects

známější pod zkratkou PDO. Jak název napovídá, je to objektové rozhraní databází pro PHP. Procedurální rozhraní budeme hledat marně.

Jako obvykle zde jako první předvedu poněkud nešikovný kód odvozený z předchozích příkladů.

<?php
class Adresar{

  private $spojeni;
  private $navrat;
  private $seznam;

  function __construct($host,$user,$pass,$name){
    $this->spojeni= @new PDO("mysql:host=$host;dbname=$name",$user,$pass);
    if ($this->spojeni->errorCode()) {
      throw new Exception($this->spojeni->errorCode());
    }
    $this->spojeni->query("SET NAMES utf8");
  }

  function query($query) {
    $this->navrat=$this->spojeni->query($query);
    if(!$this->navrat) {
      throw new Exception($this->navrat->errorCode());
    }
    $this->seznam=$this->navrat->fetchAll(PDO::FETCH_ASSOC);
    if(!sizeof($this->seznam)) {
      throw new Exception("Tabulka je prázdná");
    }
  }

  function getHeaders(){
    return array_keys($this->seznam[0]);
  }

  function getRows(){
    return $this->seznam;
  }
}

try{
  $adresar=new Adresar("localhost","kit","","test");
  $adresar->query("SELECT * FROM adresar");
  $row=$adresar->getHeaders();
  echo("<table border=\"1\">\n");
  echo("<tr>\n");
  foreach($row as $value) {
    echo("<th>".$value."</th>\n");
  }
  echo("</tr>\n");
  foreach($adresar->getRows() as $row){
    echo("<tr>");
    foreach($row as $value) {
      echo("<td>".htmlspecialchars($value)."</td>");
    }
    echo("</tr>\n");
  }
  echo("</table>\n");
} catch(Exception $e) {
  echo "Tabulku nelze vypsat<br />\n";
  echo $e->getMessage(),"\n";
}

Je vidět, že prostou výměnou ovladače jsem prakticky nic nezískal. Je tedy potřeba se podívat do manuálu a vyždímat z PDO co umí. Na prvním místě bych uvedl výjimky. Jen je potřeba ovladači sdělit, že je chceme využívat. Tím se program výrazně zkrátí, ale hlavně se mi už nestane, že bych zapomněl otestovat výsledek některého dotazu.

<?php
class Adresar{

  private $spojeni;
  private $navrat;
  private $seznam;

  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) {
    $this->navrat=$this->spojeni->query($query);
    $this->seznam=$this->navrat->fetchAll(PDO::FETCH_ASSOC);
    if(!sizeof($this->seznam)) {
      throw new Exception("Tabulka je prázdná");
    }
  }

  function getHeaders(){
    return array_keys($this->seznam[0]);
  }

  function getRows(){
    return $this->seznam;
  }
}

// pokračování viz předchozí příklad

V uvedeném příkladu jsem změnil pouze třídu Adresar, zbytek skriptu jsem ponechal beze změny. Je vidět, že ke zpřehlednění opravdu došlo, přitom chyby jsou stále ošetřeny. Navíc se mi podařilo při otvírání databáze vpašovat první SQL dotaz "SET NAMES utf8". Tento příkaz (místo "utf8" může být "cp1250" či "latin2" podle preferencí) je nutný, jinak si databáze bude myslet, že ukládaná data budou ve švédském kódování.

A jako vždy se mi to nelíbí, protože je toho psaní stále příliš mnoho. Pustím se tedy do optimalizace. Zde je kompletní řešení v mém stylu:

<?php
class Adresar{

  private $spojeni;
  private $navrat;
  private $seznam;

  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);
    $this->navrat=$this->spojeni->query("SELECT * FROM adresar");
    $this->seznam=$this->navrat->fetchAll(PDO::FETCH_ASSOC);
    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;
  }
}

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

Tentokrát jsem se s tím tolik nepáral a nacpal SQL dotaz přímo do konstruktoru třídy Adresar. Není to zrovna ideální, protože málokdy potřebujeme databázi položit jediný dotaz a opakované otevírání databáze je drahé (časově náročné). Nabízí se tedy otevírat databázi mimo třídu Adresar, trochu si ji vylepšit a předat ji konstruktoru třídy Adresar jako objekt. Bude to sice o trochu delší, ale při vícenásobném použití se mi to bohatě vrátí. O tom však až příště.


 

  Aktivity (1)

Č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 (5 hlasů) :
4444 4


 



 

 

Komentáře

Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:

PDO vypadá dobře. Bude něco i o vkládání atributů do query?

Odpovědět 7.7.2012 9:45
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Ve 4. dílu mám už lehkou přípravu na atributy, ale ještě nejsou použity. Do query se však už atributy vkládat nebudou, pouze odkazy.

Odpovědět 7.7.2012 9:51
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Michal Žůrek (misaz):

Ahoj,
teprve začínám... a samozřejmě mám malý problém:

$dsn = 'mysql:dbname=moje_prvni_database;host=localhost:888';
$user = '';
$password = '';
$db = new PDO($dsn, $user, $password);

localhost mám na pórtu 888. Přidal jsem si v myphpadmin databázi moje_prvni_database a vní tabulku lide, ale to mi (po asi 5min) napíše tyto chyby:

Warning: PDO::__construct(): MySQL server has gone away in D:\xampp\htdocs\devbook\index.php on line 5

Warning: PDO::__construct(): Error while reading greeting packet. PID=5832 in D:\xampp\htdocs\devbook\index.php on line 5

Fatal error: Maximum execution time of 30 seconds exceeded in D:\xampp\htdocs\devbook\index.php on line 5
Odpovědět 10.6.2013 20:20
Nesnáším {}, proto se jim vyhýbám.
Avatar
mkub
Redaktor
Avatar
Odpovídá na Kit
mkub:

asi aj ja prejdem na PDO... kto sa ma vyznat v tom chaose PHP kodu a vypisu do stranky?

 
Odpovědět 17.11.2013 13:49
Avatar
Kit
Redaktor
Avatar
Odpovídá na mkub
Kit:

Oceníš hlavně prepared statements, které v tomto článku nejsou, ale bez nich by PDO bylo jen poloviční.

Odpovědět 17.11.2013 13:58
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
mkub
Redaktor
Avatar
 
Odpovědět 17.11.2013 14:05
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 6 zpráv z 6.