OOP v PHP: Využití OOP v praxi
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.
Mohlo by vás také zajímat
-
Webdesign: Jak optimalizovat tlačítka na webu
7. března 2024 -
Monitory OLED: klíčové pojmy a funkce
13. května 2024
Nejnovější
-
Šokující data od Microsoftu: Kyberútoky rostou o stovky procent!
8. listopadu 2024 -
Chcete jedinečnou doménu? Objevte koncovky FOOD, MEME a MUSIC!
7. listopadu 2024 -
OpenAI představilo novou funkci ChatGPT Search
6. listopadu 2024 -
Windows App: Pracujte odkudkoliv, kdykoliv
3. listopadu 2024
Jsef
Pro 8, 2011 v 19:35Č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
Dub 22, 2012 v 9:54Kdepak se dají stáhnout ty podklady k článku….?
Aleš
Kvě 6, 2012 v 11:52Stejný problém… Podklady prostě asi nejsou a nebudou…:-/ Škoda…