Reklama

interval.cz

OOP v PHP: Využití OOP v praxi

15. 02. 2006 | Jakub Mrozek | PHP | Komentáře: 3

Po dlouhé teorii přichází na řadu praxe. V následujícím textu si vysvětlíme možnosti přístupu k databázi pomocí různých vzorů objektově orientovaného programování v PHP.

Představme si například internetový obchod, který pracuje s MySQL. Běžný e-shop může mít i několik desítek tisíc řádků kódu. Pokud se změní syntaxe jazyka nebo budete chtít změnit typ databáze, znamená to, že musíte projít všechny řádky kódu a zápis změnit. S OOP tento problém vyřešíte během několika málo minut.

Funkce pracující se syntaxí SQL totiž nejsou součástí procedurálního uspořádání kódu, jsou vázány v objektech, a tak změna jednoho zápisu ovlivní chování celého kódu, který tuto třídu využívá.

Zadání

Naším cílem bude vytvořit kód rozhraní, které umožní komunikaci s databází MySQL i SQLite (případně dalších) s tím, že výběr typu databáze umožníme pouhou změnou jedné hodnoty proměnné. Při tvorbě aplikace využijeme abstraktní třídu, implementace rozhraní, dereference objektů a podobně.

Přípravy

Nejprve je třeba vytvořit databáze v SQLite i MySQL, vytvořit tabulky a databázi naplnit daty. Stáhněte si proto pomocný skript, který za vás vytvoří stejnou tabulku v MySQL i SQLite a naplní ji 150 náhodnými záznamy (v phpMyAdmin je třeba vytvořit databázi "oop").

Vytvoření proměnných a vzoru Factory

Nejprve si vytvoříme několik proměnných, které budou obsahovat informace o připojení a typ databáze. Pak pomocí vzoru factory zavoláme různou třídu podle hodnoty proměnné $type:

<?php
$typ      = 'SQLite';
$host     = 'localhost';
$uzivatel = '';
$heslo    = '';
$databaze = 'oop'; 

function Factory($typ,$host,$uzivatel,$heslo,$databaze){
    if($typ == 'MySQL'){
      return new MySQL($host,$uzivatel,$heslo,$databaze);
    }else if($typ == 'SQLite'){
      return new SQLite($databaze);
    }else{
      return FALSE;
    }
}
?>

Třídě MySQL předáváme čtyři proměnné, třídě SQLite je třeba předat pouze název databáze.

Definice tříd MySQL a SQLite a rozhraní

Pro obě třídy MySQL a SQLite vytváříme stejnou strukturu, vytvoříme si tedy rozhraní, které obě třídy implementují. Funkce obou tříd je vytvoření spojení s příslušnou databází a volání další třídy, která provádí hlavní logiku operací:

<?php
  interface Spojeni{
    public function spojeni();
    public function dotaz($dotaz);
  } 

  class MySQL implements Spojeni{
    protected $host;
    protected $uzivatel;
    protected $heslo;
    protected $databaze;
    protected $spoj;
    public function __construct($host,$uzivatel,$heslo,$databaze){
      $this->host     = $host;
      $this->uzivatel = $uzivatel;
      $this->heslo    = $heslo;
      $this->databaze = $databaze;
    }
    public function spojeni(){
      @$this->spoj = mysql_connect($this->host,$this->uzivatel,$this->heslo) or die('Spojení se nezdařilo');
      @mysql_select_db($this->databaze, $this->spoj) or die('Databáze neexistuje'); 

    }
    public function dotaz($dotaz){
      if(!$this->spoj){
        $this->spojeni();
      }
      return new VraceniDotazuMySQL($this->spoj,$dotaz);
    }
  } 

  class SQLite implements Spojeni{
    public $databaze;
    public $spoj;
    public function __construct($databaze){
      $this->databaze = $databaze;
    }
    public function spojeni(){
      $this->spoj = sqlite_open($this->databaze) or die('Spojení se nezdařilo');
      }
    public function dotaz($dotaz){
      if(!$this->spoj){
        $this->spojeni();
      }
      return new VraceniDotazuSQLite($this->spoj,$dotaz);
    }
  }
?>

Definice tříd VraceniDotazuMySQL a VraceniDotazuSQLite a abstraktní třídy

Nejprve vytvoříme abstraktní třídu. Proč nevytváříme rozhraní? Obsahuje totiž jednu metodu, která bude ve všech třídách stejná, a tak je jednodušší tuto metodu definovat jako abstraktní. Připomínám, že abstraktní třída se neimplementuje, ale dědí (nemůže sama vytvářet instance).

<?php
  abstract class VraceniDotazu{
  abstract public function Vlozeni();
  abstract public function VratPole();
  public function Pole(){
      $pole = array();
      while ($radek = $this->VratPole()){
        $pole[] = $radek;
      }
      return $pole;
    }
  }
?>

Dále vytváříme třídy VraceniDotazuMySQL a VraceniDotazuSQLite. Konstruktor přiřazuje hodnoty předaným vlastnostem. Metoda Vlozeni() nejprve vytváří pole z argumentů, které metodě byly přiřazeny. Pak pomocí cyklu foreach připravíme dotaz pro databázi. Metoda VratPole() už následně vytváří pole hodnot, které jsme získali z databáze. K syntaxi dotazů se ještě později vrátíme.

<?php
  class VraceniDotazuMySQL extends VraceniDotazu{
    protected $spojeni;
    protected $dotaz;
    protected $argumenty;
    protected $vysledek;
    public function __construct($spojeni, $dotaz){
      $this->spojeni = $spojeni;
      $this->dotaz   = $dotaz;
    }
    public function Vlozeni(){
      $argumenty = func_get_args();
      foreach ($argumenty as $index => $hodnota){
        $this->argumenty[$index + 1] = $hodnota;
      }
      $pocet_argumentu = count($argumenty);
      $dotaz = $this->dotaz;
      foreach($this->argumenty as $index => $hodnota){
        $dotaz = str_replace(":$index","'".mysql_escape_string($hodnota)."'", $dotaz);
      }
      $this->vysledek = mysql_query($dotaz);
      if(!$this->vysledek){
        return FALSE;
      }
      return $this;
    }
    public function VratPole(){
      return mysql_fetch_array($this->vysledek);
    }
  } 

  class VraceniDotazuSQLite extends VraceniDotazu{
    protected $spojeni;
    protected $dotaz;
    protected $argumenty;
    protected $vysledek;
    public function __construct($spojeni, $dotaz){
      $this->spojeni = $spojeni;
      $this->dotaz   = $dotaz;
    }
    public function Vlozeni(){
      $argumenty = func_get_args();
      foreach ($argumenty as $index => $hodnota){
        $this->argumenty[$index + 1] = $hodnota;
      }
      $pocet_argumentu = count($argumenty);
      $dotaz = $this->dotaz;
      foreach($this->argumenty as $index => $hodnota){
        $dotaz = str_replace(":$index","'".sqlite_escape_string($hodnota)."'", $dotaz);
      }
      $this->vysledek = sqlite_query($this->spojeni, $dotaz);
      if(!$this->vysledek){
        return FALSE;
      }
      return $this;
    }
    public function VratPole(){
      return sqlite_fetch_array($this->vysledek);
    }
  }
?>

Dotazy na databázi

Když máme rozhraní připravené, můžeme zadávat dotazy a výsledky vypisovat:

<?php
$dotaz = "SELECT * FROM tab WHERE jmeno = :1"; 

$ins = Factory($typ,$host,$uzivatel,$heslo,$databaze);
$jm = "jmeno".rand(1,10)."jmeno"; 

$d = $ins->dotaz($dotaz)->Vlozeni($jm)->Pole(); 

echo '<table>';
  for($i = 0; $i < count($d);$i++){
    echo '<tr><td>'.$d[$i][id].'</td>
          <td>'.$d[$i][jmeno].'</td>
          <td>'.$d[$i][prijmeni].'</td></tr>';
  }
echo '</table>';
?>

Proč mají dotazy syntaxi SELECT * FROM tab WHERE jmeno = :1? Takový dotaz stačí použít jednou a pak už jen měníme argumenty, tedy další dotazy by například mohly vypadat takto:

<?php
$d = $ins->dotaz($dotaz)->Vlozeni('Nějaké jméno')->Pole();
?>

Jelikož metoda Vlozeni() umožňuje přeměnu libovolného počtu předaných argumentů, můžeme používat dotazy typu:

<?php
$dotaz = "SELECT * FROM tab WHERE jmeno = :1 AND prijmeni = :2";
$d = $ins->dotaz($dotaz)->Vlozeni('Nějaké jméno','Nějaké prijmeni')->Pole();
?>

Díky takovému zápisu rovněž můžeme dotazy přizpůsobovat libovolnému typu databáze.

Pro další studium a testování si stáhněte podklady k příkladu.

Pozn. red.: Zdůrazňujeme, že tento text se týká PHP 5.


Další aktuální články na interval.cz

Tematicky související články

Dejte vědět i ostatním o článku

Komentáře ke článku

Přidat nový komentář

Jsef

Autor komentáře: Jsef

Datum vložení: 08. Prosinec 2011, 19:35:09

Článek dobrý, jen trochu neužitečný. Píše se v něm o různém stahování podkladů, ale nikde není nic ke stažení. V takovém případě je celý článek k ničemu...

martin

Autor komentáře: martin

Datum vložení: 22. Duben 2012, 09:54:15

Kdepak se dají stáhnout ty podklady k článku....?

Aleš

Autor komentáře: Aleš

Datum vložení: 06. Květen 2012, 11:52:00

Stejný problém... Podklady prostě asi nejsou a nebudou...:-/ Škoda...

Zpět na začátek komentářů | Zpět na začátek článku

Přidat nový komentář

Jméno a e-mail jsou nepovinné. Příspěvky obsahující odkaz jsou moderovány.

Reklama
Reklama

Syndikace

hledáme nové autory | redakce interval.cz | reklama na interval.cz

© ZONER software, a.s., všechna práva vyhrazena. Hosting zajišťuje CZECHIA.COM. SSL certifikáty pro domény. Powered by WordPress.