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

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

Zde je pokračování úvodního článku http://www.itnetwork.cz/…iho-ovladace

Tentokrát jsem použil novejší ovladač MySQLi. Bohužel s ním mnoho zkušeností nemám, ale nemohu ho ignorovat. V uvedeném příkladu se moc neprojeví jeho přednosti, ale snad to nebude na škodu.

Nejprve jsem se pokusil o klasický procedurální kód. Výjimky jsou však pouze objektové, proto je ponechám.

<?php
try {
  $spojeni=@mysqli_connect("localhost","kit","","test");
  if (!$spojeni) {
    throw new Exception(mysqli_connect_error(), mysqli_connect_errno());
  }
  mysqli_query($spojeni,"SET NAMES utf8");
  $navrat=@mysqli_query($spojeni,"SELECT * FROM adresar");
  if(!$navrat) {
    throw new Exception(mysqli_stmt_error($navrat), mysqli_stmt_errno($navrat));
  }
  $row=mysqli_fetch_assoc($navrat);
  if(!isset($row)) {
    throw new Exception("Tabulka je prázdná");
  }
  echo("<table border=\"1\">\n");
  echo("<tr>\n");
  foreach($row as $key => $value) {
    echo("<th>".$key."</th>\n");
  }
  echo("</tr>\n");
  mysqli_data_seek($navrat,0);
  while ($row = mysqli_fetch_assoc($navrat)){
    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 patrné, že se tato procedurální verze příliš neliší od předchozí verze základního ovladače MySQL. Výhoda MySQLi se projeví až při použití parametrizovaných dotazů a dalších pokročilých funkcí. Také se projeví na výkonu, neboť MySQLi je rychlejší.

Nyní následuje pokus o objektové řešení aplikace. Snažil jsem se přiblížit objektovému programování, jak ho vidím v různých návodech.

<?php
class Adresar{

  private $spojeni;
  private $navrat;

  function __construct($host,$user,$pass,$name){
    $this->spojeni= @new mysqli($host,$user,$pass,$name);
    if ($this->spojeni->connect_error) {
      throw new Exception($this->spojeni->connect_error, $this->spojeni->connect_errno);
    }
    $this->spojeni->query("SET NAMES utf8");
  }

  function query($query) {
    $this->navrat=$this->spojeni->query($query);
    if(!$this->navrat) {
      throw new Exception($spojeni->error, $spojeni->errno);
    }
  }

  function getHeaders(){
    $row=$this->navrat->fetch_assoc();
    if(!isset($row)) {
      throw new Exception("Tabulka je prázdná");
    }
    return $row;
  }

  function getRows(){
    $rows=array();
    $this->navrat->data_seek(0);
    while ($row = $this->navrat->fetch_assoc()){
      $rows[]=$row;
    }
    return $rows;
  }
}

try{
  $db=new Adresar("localhost","kit","","test");
  $db->query("SELECT * FROM adresar");
  $row=$db->getHeaders();
  echo("<table border=\"1\">\n");
  echo("<tr>\n");
  foreach($row as $key => $value) {
    echo("<th>".$key."</th>\n");
  }
  echo("</tr>\n");
  foreach($db->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";
}

Jak je vidět, program se mi trochu prodloužil. Ani se mi v této podobě moc nelíbí. Pokusím se tedy přepsat ho do podoby, která je mi bližší:

<?php
class Adresar{

  private $spojeni;
  private $navrat;
  private $head;
  private $adr;

  function __construct($host,$user,$pass,$name){
    $this->spojeni= @new mysqli($host,$user,$pass,$name);
    if ($this->spojeni->connect_error) {
      throw new Exception($this->spojeni->connect_error, $this->spojeni->connect_errno);
    }
    $this->spojeni->query("SET NAMES utf8");
  }

  function precti() {
    $this->navrat=$this->spojeni->query("SELECT * FROM adresar");
    $this->head=$this->navrat->fetch_assoc();
    if(!isset($this->head)) {
      throw new Exception("Tabulka je prázdná");
    }
    $this->navrat->data_seek(0);
    if(!$this->navrat) {
      throw new Exception($spojeni->error, $spojeni->errno);
    }
    $this->adr=$this->navrat->fetch_all();
  }

  function __toString() {
    $headers='<tr><th>'.implode('</th><th>',array_keys($this->head)).'</th></tr>';
    $rows=array();
    foreach($this->adr 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");
  $adresar->precti();
  echo $adresar;
} catch(Exception $e) {
  echo "Tabulku nelze vypsat<br />\n";
  echo $e->getMessage(),"\n";
}

Ještě stále to není ono. SQL dotazy jsou již odděleny od prezentace v HTML, program je o něco kratší a snad i přehlednější, ale testování návratové hodnoty po každém volání SQL dotazu nevypadá právě ideálně. Výsledek jednoho z dotazů jsem ani netestoval, i když bych vlastně měl.

Hodilo by se mi, kdyby se po každé chybě při práci s databází automaticky vyhodila výjimka. Možná to v MySQLi nějak jde, ale rozumný návod jsem nenašel. Řešení jsem však objevil v ovladači PDO, o kterém bude třetí pokračování tohoto seriálu.


 

  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 (2 hlasů) :
3.53.53.53.5 3.5


 



 

 

Komentáře

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

V první verzi jsi vlastně nasimuloval práci se starším ovladačem MySQL pomocí MySQLi. Podle mne by bylo lepší použít procedurální volání, např:

mysqli_query(...);

Přiznávám, že druhá verze je mi docela blízká, nějaký podobný wrapper bych si asi napsal.

Poslední verze je zajímavá, hlavně použití implode. Nesedí mi ale název třídy MyDB, když třída reprezentuje adresář. Jako logičtější bych viděl třídu Adresar s přetíženým __toString, tam by dávalo smysl, že:

echo adresar;

vypíše adresář. Podobný princip používám v C#, kde je ORM (LINQ). Ten vytvoří DB třídy. Já si je poté rozšířím pomocí partial class a přidám jim ToString().

V PHP mám s tímto problém, protože zde jsem s ORM nedělal. Vím, že ty ORM příliš nectíš, jak tedy řešíš tvorbu objektů z query?
Já to mám zatím tak, že když to nepotřebuji, tak si objekty netvořím (např. chci jen 1 atribut odněkud), ale občas něco používám tak často, že se mi vyplatí tomu udělat třídu a tu naplnit daty na začátku požadavku na server. Musím si to samozřejmě ručně namapovat v konstruktoru a to je docela otrava. Říkal jsem si, že by šlo nějakou magií naplnit atributy objektu sloupci z DB (kdyby měly stejný název), jen nevím, jestli se to sluší a patří.

Odpovědět 6.7.2012 10:10
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:

Možná bych první příklad ještě mohl předělat na mysqli_query(), aby si i odpůrci objektů přišli na své :)

Také jsem nad názvem třídy MyDB váhal a zřejmě Adresar by byl vhodnější název. Nevím, jestli to ještě má smysl měnit v tomto článku, ale v PDO (které je mi bližší) to spravím. Ke tvorbě objektů z dotazu se časem také dostanu.

Na naplnění atributů objektu sloupci z DB není třeba magie. Na to stačí metoda MySQLi::fetch_a­ll(), resp. PDO::fetchAll(). Samozřejmě se k tomu používá jen jedna privátní proměnná. Pokud potřebuji konkrétní názvy sloupců, upravím si je přímo v SQL dotazu.

Odpovědět 6.7.2012 11:32
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Jo, když už procedurálně, tak bych tak volal i MySQLi. Ani ne pro nepřizpůsobivé odpůrce objektů (ty na tomto webu ani nechceme a rozhodně pro ně nebudeme něco psát), ale pro začátečníky, kteří nevědí, co to objekt je. Názory na začátky v programování se liší, já zatím myslím, že by měl člověk začít bez objektů a poté na ně brzy navázat, jinak je toho hodně najednou. Někdo říká, že by měl začít přímo v neobjektovém jazyce, někdo že má začít objekty. Psát procedurálně v obj. jazyce mi přijde jako dobrý kompromis pro osvojení základů.

Třídu bych přejmenoval.

To fetchAll ale vrací nějaký svůj objekt ne? Já chci, aby data byla v instanci mé třídy. Tedy abych napsal např.:

$diar = new Diar();
// konstruktor načte data
echo $diar->dnes();
echo $diar->majitel;

Tedy abych mohl volat své metody a přistupovat k získaným atributům z DB. Teď mám v konstruktoru mraky dosazení do atributů.

Odpovědět 7.7.2012 9:03
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:

Však jsem první příklad přepsal a třídu přejmenoval.

Metoda MySQLi::fetch_all() vrací obyčejné nebo asociativní pole. Seznam objektů umí až PDO::fetchAll(). Možná to dám do 5. dílu.

MySQLi se už déle zabývat nebudu. Beru ho jen jako mezičlánek. Je lepší, než původní ovladač, ale na PDO nemá.

Odpovědět 7.7.2012 9:33
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Aha, jsem si nevšiml, promiň :)

Jo, tak v PDO, jestli lze, aby to naplnilo daty instanci mé třídy.

Odpovědět 7.7.2012 9:49
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:

PDO::fetch() umí vrátit objekt, PDO::fetchAll() pole objektů. Mělo by to stačit.

Odpovědět 7.7.2012 9:54
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Marek Šafránek:

takže jako začátečník bych měl ideálně začít s PDO nebo MySQLi?:) A naučit se dobře oba způsoby?

Odpovědět 2.3.2015 14:50
Stojí-li něco za námahu, je třeba to udělat pořádně...
Avatar
Odpovídá na Marek Šafránek
Martin Konečný (pavelco1998):

Doporučuji určitě PDO, umí toho víc než MySQLi a myslím, že ti PDO bude bohatě stačit :)

 
Odpovědět  +1 2.3.2015 15:06
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 8 zpráv z 8.