Programátorská sociální síť a materiálová základna pro C#, Java, PHP, HTML, CSS, JavaScript a další.


Přihlásit se Registrace  

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

Zpět do sekce Práce s MySQL a dalšími databázemi v PHP

Zde je pokračování úvodního článku http://www.devbook.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.


 

Autor: Kit
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 vám líbí článek?
Celkem (1 hlasů):
4 4 4 4 4


 


Předchozí článek
Práce s MySQL v PHP - použití základního ovladače
S databází MySQL je možné v PHP pracovat různými metodami s použitím různých ovladačů. Některé jsou zastaralé, jiné moderní. Vyberte si.
Všechny články v sekci
Práce s MySQL a dalšími databázemi v PHP
Série článků se věnuje různým přístupům pro práci s databází v PHP. Jsou probrány ovladače MySQL, MySQLi, PDO a různé objektové přístupy k datům.
Další článek
Práce s MySQL v PHP - Použití ovladače PDO
Databáze MySQL se dá z PHP ovládat pomocí tří ovladačů. Nejnovější PDO vytváří společné rozhraní pro více druhů databází a vytváří těsnější vazbu na PHP.


 

 

Vaše komentáře:

06.07.2012 10:10:06
Avatar
sdraco
Moderátor
Skill: Kvantový počítač
DotDotDotDotDotDotDotDotDotDot

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   i++; | i--;
Čtverec, čtverec, čtverec, čtverec.
06.07.2012 11:32:06
Avatar
Kit
Moderátor
Skill: Mainframe
DotDotDotDotDotDotDotDotDotDot
Odpovídá na sdraco:

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   i++; | i--;
Aplikace je hotova až tehdy, když z ní nelze nic odebrat.
07.07.2012 09:03:46
Avatar
sdraco
Moderátor
Skill: Kvantový počítač
DotDotDotDotDotDotDotDotDotDot
Odpovídá na Kit:

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   i++; | i--;
Čtverec, čtverec, čtverec, čtverec.
07.07.2012 09:33:03
Avatar
Kit
Moderátor
Skill: Mainframe
DotDotDotDotDotDotDotDotDotDot
Odpovídá na sdraco:

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   i++; | i--;
Aplikace je hotova až tehdy, když z ní nelze nic odebrat.
07.07.2012 09:49:35
Avatar
sdraco
Moderátor
Skill: Kvantový počítač
DotDotDotDotDotDotDotDotDotDot
Odpovídá na Kit:

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

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


Odpovědět   i++; | i--;
Čtverec, čtverec, čtverec, čtverec.
07.07.2012 09:54:48
Avatar
Kit
Moderátor
Skill: Mainframe
DotDotDotDotDotDotDotDotDotDot
Odpovídá na sdraco:

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


Odpovědět   i++; | i--;
Aplikace je hotova až tehdy, když z ní nelze nic odebrat.

 

Zobrazeno 6 z 6 zpráv


Přidat novou zprávu

Avatar
Neregistrovaný

Pro výhody se přihlaš. Pokud ještě nemáš účet, zaregistruj se.

Jméno:
E-mail:
Web:

Šťastný Smutný S vyplazeným jazykem Mrkající Smějící se Plačící Cool Nemocný Naštvaný S brýlemi Stydící se On to nebyl Překvapený Hodně překvapený Šokovaný Srdce sdraco
Vložení obrázků Obrázky mohou nahrávat pouze registrovaní uživatelé
Vložení dlouhého zdrojáku Pouze pro registrované

 

Pro ověření prosím zaškrtněte pravdivá tvrzení:
Registrovaní uživatelé se tímto zdržovat nemusí. Zaregistrovat se

Budu respektovat pravidla
Nejsem člověk
Nehodlám dodržovat pravidla
Píši proto, že zpráva má užitečnou hodnotu