Jak konfigurovat a používat PDO pro přístup k databázi v systému Linux

  • Richard Poole
  • 0
  • 1679
  • 326
>

Objektivní

Naučte se, jak konfigurovat a používat PDO pro přístup do databáze: od chybových režimů po metody načítání.

Požadavky

  • Standardní znalost MySQL a mysql klient příkazového řádku;
  • Seznámit se se základními koncepty objektově orientovaného programování
  • PHP> = 5.1
  • Máte funkční databázi MySQL / MariaDB

Obtížnost

STŘEDNÍ

Konvence

  • # - vyžaduje, aby dané linuxové příkazy byly prováděny s oprávněním root buď přímo jako uživatel root, nebo pomocí sudo příkaz
  • $ - vyžaduje, aby dané linuxové příkazy byly prováděny jako běžný neprivilegovaný uživatel

Úvod

PDO je zkratka pro Datové objekty PHP: je to rozšíření PHP pro interakci s databázemi pomocí objektů. Jedna z jeho silných stránek spočívá ve skutečnosti, že není striktně vázána na určitou konkrétní databázi: její rozhraní poskytuje mimo jiné běžný způsob přístupu k několika různým prostředím:
  • MySQL
  • SQLite
  • PostgreSQL
  • Microsoft SQL Server
Tato příručka si klade za cíl poskytnout zcela ucelený přehled o PDO, který provede čtenáře krok za krokem od navázání připojení k databázi až po výběr nejvhodnějšího režimu načítání, ukazuje, jak vytvořit připravené příkazy a popisuje možné chybové režimy.

Vytvořte testovací databázi a tabulku

První věcí, kterou uděláme, je vytvoření databáze pro tento tutoriál:
VYTVOŘIT DATABÁZE solar_system; UDĚLTE VŠECHNY VÝSADY NA solar_system. * TO 'testuser' @ 'localhost' IDENTIFIKOVÁNO 'testpassword'; 
Udělili jsme uživateli testuser všechna oprávnění na Sluneční Soustava databáze pomocí testovací heslo jako heslo. Nyní vytvořme tabulku a vyplňme ji některými údaji (není určena astronomická přesnost):
USE solar_system; VYTVOŘIT TABULKU planety (id TINYINT (1) BEZ ZNAČENÍ NENÍ NULL AUTO_INCREMENT, PRIMÁRNÍ KLÍČ (id), jméno VARCHAR (10) NENÍ NULL, barva VARCHAR (10) NENÍ NULL); INSERT INTO planet (name, color) VALUES ('earth', 'blue'), ('mars', 'red'), ('jupiter', 'divný'); 

DSN: Název zdroje dat

Nyní, když máme databázi, musíme definovat a DSN. DSN znamená Název zdroje dat, a je to v podstatě sada informací potřebných pro připojení k databázi, představovaná ve formě řetězce. Syntaxe se může lišit v závislosti na databázi, ke které se chcete připojit, ale protože interagujeme s MySQL / MariaDB, poskytneme:
  • Typ ovladače, který se má použít pro připojení
  • Název hostitele zařízení hostujícího databázi
  • Port, který se má použít pro připojení (volitelně)
  • Název databáze
  • Sada znaků (volitelně)
Formát řetězce by v našem případě byl následující (uložíme jej do souboru $ dsn proměnná):
$ dsn = "mysql: host = localhost; port = 3306; dbname = solar_system; charset = utf8"; 
Nejprve jsme poskytli předpona databáze. V tomto případě, protože se připojujeme k databázi MySQL / MariaDB, jsme použili mysql. Potom jsme oddělili předponu od zbytku řetězce dvojtečkou a každou další část středníkem.
V následujících dvou částech jsme specifikovali název hostitele počítače, na kterém je databáze hostována, a přístav použít pro připojení. Pokud tento není k dispozici, použije se výchozí, což je v tomto případě 3306. Ihned poté, co jsme poskytli jméno databáze, a po něm znaková sada použít.

Vytvoření objektu PDO

Nyní, když je naše DSN připraveno, budeme stavět Objekt PDO. Konstruktor PDO vezme řetězec dsn jako první parametr, jméno uživatele v databázi jako druhý parametr, jeho heslo jako třetí a volitelně pole možností jako čtvrtý:
$ options = [PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION, PDO :: ATTR_DEFAULT_FETCH_MODE => PDO :: FETCH_ASSOC]; $ pdo = nový CHOP ($ dsn, 'testuser', 'testpassword', $ options); 
Možnosti však lze zadat i poté, co byl objekt vytvořen, pomocí SetAttribute () metoda:
$ pdo-> SetAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); 

Nastavení chování PDO při chybách

Pojďme se podívat na některé z dostupných možností PDO :: ATTR_ERRMODE. Tato možnost je opravdu důležitá, protože definuje chování PDO v případě chyb. Možné možnosti jsou:

PDO :: ERRMODE_SILENT

Toto je výchozí nastavení. PDO pouze nastaví chybový kód a chybovou zprávu. Lze je získat pomocí chybový kód() a errorInfo () metody.

PDO :: ERRMODE_EXCEPTION

Toto je podle mého názoru doporučeno. U této možnosti PDO kromě nastavení chybového kódu a informací vyvolá a Výjimka PDO, což přeruší tok skriptu a je to užitečné zejména v případě Transakce CHOP (uvidíme, jaké transakce budou později v tomto kurzu).

PDO :: ERRMODE_WARNING

U této možnosti nastaví PDO chybový kód a informace jako indexované PDO :: ERRMODE_SILENT, ale také vypíše a VAROVÁNÍ, což nezruší tok skriptu.

Nastavení výchozího režimu načítání

Další důležité nastavení lze zadat pomocí PDO :: DEFAULT_FETCH_MODE. konstantní. Umožňuje určit výchozí metodu načítání, která se použije při načítání výsledků z dotazu. Toto jsou nejčastěji používané možnosti:

PDO :: FETCH_BOTH:

Toto je výchozí nastavení. Výsledek získaný vyhledávacím dotazem bude indexován jak celým číslem, tak názvem sloupce. Použití tohoto režimu načítání při načítání řádku z tabulky planet by nám poskytlo tento výsledek:

$ stmt = $ pdo-> dotaz ("VÝBĚR * Z FONDŮ"); $ results = $ stmt-> načíst (PDO :: FETCH_BOTH); 
 Pole ([id] => 1 [0] => 1 [název] => země [1] => země [barva] => modrá [2] => modrá) 

PDO :: FETCH_ASSOC:

Při použití této možnosti bude výsledek uložen do souboru asociativní pole ve kterém každý klíč bude název sloupce a každá hodnota bude odpovídající hodnotou v řádku:

$ stmt = $ pdo-> dotaz ("VÝBĚR * Z FONDŮ"); $ results = $ stmt-> načíst (PDO :: FETCH_ASSOC);
 Pole ([id] => 1 [název] => země [barva] => modrá) 

CHOP :: FETCH_NUM

Tento režim načítání vrátí načtený řádek do a 0-indexované pole:

 Pole ([0] => 1 [1] => země [2] => modrá) 

CHOP :: FETCH_COLUMN

Tato metoda načítání je užitečná při načítání pouze hodnot sloupce a vrátí všechny výsledky uvnitř prostého jednorozměrného pole. Například tento dotaz:

$ stmt = $ pdo-> dotaz ("VYBRAT název Z planet");
Vrátí tento výsledek:
 Pole ([0] => Země [1] => Mars [2] => Jupiter) 

PDO :: FETCH_KEY_PAIR

Tato metoda načítání je užitečná při načítání hodnot pouze 2 sloupců. Vrátí výsledky ve formě asociativního pole, ve kterém budou hodnoty načtené z databáze pro první zadaný sloupec v dotazu použity jako klíče pole, zatímco hodnoty načtené pro druhý sloupec budou představovat asociativní pole hodnoty pole:

$ stmt = $ pdo-> dotaz ("VYBRAT jméno, barva Z planet"); $ result = $ stmt-> fetchAll (PDO :: FETCH_KEY_PAIR); 
Vrátí se:
 Pole ([země] => modrá [mars] => červená [jupiter] => zvláštní) 

PDO :: FETCH_OBJECT:

Při použití PDO :: FETCH_OBJECT konstantní, an anonymní objekt bude vytvořen pro každý načtený řádek. Jeho (veřejné) vlastnosti budou pojmenovány po sloupcích a výsledky dotazu budou použity jako jejich hodnoty. Použití tohoto režimu načítání na stejný dotaz výše by nám vrátilo výsledek ve tvaru:

$ results = $ stmt-> načíst (PDO :: FETCH_OBJ);
 stdClass Object ([name] => earth [color] => blue) 

PDO :: FETCH_CLASS:

Tento režim načítání, stejně jako výše, přiřadí hodnotu sloupců vlastnostem objektu, ale v tomto případě bychom měli určit existující třídu, která by měla být použita k vytvoření objektu. Ukažme si to, nejprve vytvoříme třídu:

třída Planet soukromé $ jméno; soukromá $ barva; veřejná funkce setName ($ planet_name) $ this-> name = $ planet_name;  veřejná funkce setColor ($ planet_color) $ this-> color = $ planet_color;  veřejná funkce getName () return $ this-> name;  veřejná funkce getColor () return $ this-> color;  
Ignorujte naivitu výše uvedeného kódu a všimněte si, že vlastnosti třídy Planet jsou soukromé a třída nemá žádný konstruktor. Nyní zkusme načíst výsledky.
Při použití vynést() s PDO :: FETCH_CLASS musíte použít setFechMode () metoda na objektu prohlášení před pokusem o načtení dat, například:
$ stmt = $ pdo-> dotaz ("VYBRAT jméno, barva Z planet"); $ stmt-> setFetchMode (PDO :: FETCH_CLASS, 'Planet');
Poskytli jsme konstantu možnosti načtení PDO :: FETCH_CLASS jako první argument metody setFetchMode () a název třídy, která by měla být použita k vytvoření objektu (v tomto případě 'Planet'), jako druhý. Nyní běžíme:
$ planet = $ stmt-> fetch ();
Objekt Planet měl být vytvořen:
var_dump ($ planet);
 Planet Object ([name: Planet: private] => earth [color: Planet: private] => blue) 
Všimněte si, jak byly hodnoty načtené z dotazu přiřazeny k odpovídajícím vlastnostem objektu, i když jsou soukromé.

Přiřazení vlastností po konstrukci objektu

Třída planety nemá definován žádný explicitní konstruktor, takže při přiřazování vlastností nejsou žádné problémy; ale co kdyby třída měla konstruktor, ve kterém byla vlastnost přiřazena nebo manipulována? Protože jsou hodnoty přiřazeny před voláním konstruktoru, byly by přepsány.
CHOP pomáhá poskytovat FETCH_PROPS_LATE konstanta: při jejím použití budou hodnoty přiřazeny vlastnostem po objekt je postaven. Například:
třída Planet soukromé $ jméno; soukromá $ barva; public function __construct ($ name = moon, $ color = grey) $ this-> name = $ name; $ this-> color = $ color;  veřejná funkce setName ($ planet_name) $ this-> name = $ planet_name;  veřejná funkce setColor ($ planet_color) $ this-> color = $ planet_color;  veřejná funkce getName () return $ this-> name;  veřejná funkce getColor () return $ this-> color; 
Upravili jsme naši třídu Planet a poskytli konstruktor, který bere dva argumenty: první je název a druhý je barva. Tyto argumenty mají výchozí hodnotu měsíc a šedá: to znamená, že pokud nejsou výslovně uvedeny žádné hodnoty, budou přiřazeny výchozí hodnoty.
V tomto případě, pokud nepoužíváme FETCH_PROPS_LATE, bez ohledu na hodnoty načtené z databáze budou mít vlastnosti vždy výchozí hodnoty, protože při konstrukci objektu budou přepsány. Pojďme to ověřit. Nejprve spustíme dotaz:
$ stmt = $ pdo-> dotaz ("SELECT name, color FROM solar_system WHERE name = 'earth'"); $ stmt-> setFetchMode (PDO :: FETCH_CLASS, 'Planet'); $ planet = $ stmt-> fetch ();
Pak vyložíme Planeta objekt a zkontrolujte, jaké hodnoty mají jeho vlastnosti:
var_dump ($ planet); object (Planet) # 2 (2) ["name": "Planet": private] => string (4) "moon" ["color": "Planet": private] => string (4) "grey" 
Podle očekávání byly hodnoty načtené z databáze přepsány výchozími hodnotami. Nyní si ukážeme, jak lze tento problém vyřešit pomocí FETCH_PROPS_LATE (dotaz je stejný jako výše):
$ stmt-> setFetchMode (PDO :: FETCH_CLASS | PDO :: FETCH_PROPS_LATE, 'Planet'); $ planet = $ stmt-> fetch (); var_dump ($ planet); object (Planet) # 4 (2) ["name": "Planet": private] => řetězec (5) "earth" ["color": "Planet": private] => řetězec (4) "blue" 
Nakonec jsme dosáhli požadovaných výsledků. Ale co když konstruktor třídy nemá žádné výchozí hodnoty a musí být zadány? Jednoduché: můžeme určit parametry konstruktoru ve formě pole jako třetí argument, za názvem třídy, v metodě setFetchMode (). Například pojďme změnit konstruktor:
třída Planet soukromé $ jméno; soukromá $ barva; veřejná funkce __construct ($ name, $ color) $ this-> name = $ name; $ this-> color = $ color;  […]
Argumenty konstruktoru jsou nyní povinné, takže bychom spustili:
$ stmt-> setFetchMode (PDO :: FETCH_CLASS | PDO :: FETCH_PROPS_LATE, 'Planet', ['moon', 'grey']);
V tomto případě slouží parametry, které jsme poskytli, jako výchozí hodnoty potřebné k inicializaci objektu bez chyb: budou přepsány hodnotami získanými z databáze.

Načítání více objektů

Samozřejmě je možné načíst více výsledků jako objekty, ať už pomocí vynést() metoda uvnitř while smyčky:
while ($ planet = $ stmt-> fetch ()) // dělat věci s výsledky 
nebo načtením všech výsledků najednou. V tomto případě, jak bylo uvedeno výše, pomocí fetchAll () metodu, nemusíte specifikovat režim načítání před voláním samotné metody, ale v okamžiku, kdy ji zavoláte:
$ stmt-> fetchAll (PDO :: FETCH_CLASS | PDO_FETCH_PROPS_LATE, 'Planet', ['moon', 'grey']); 

PDO :: FETCH_INTO

S touto sadou metod načítání PDO nevytvoří nový objekt, místo toho aktualizuje vlastnosti existujícího, ale pouze pokud jsou veřejnost, nebo pokud používáte __soubor magická metoda uvnitř objektu.

Připravené vs přímé výroky

PDO má dva způsoby, jak provádět dotazy: jeden je přímý, jednokrokový. Druhou, bezpečnější je použití připravená prohlášení.

Přímé dotazy

Při použití přímých dotazů máte dvě hlavní metody: dotaz() a exec (). První výnosy vrátí a PDOStatemnt objekt, který můžete použít k přístupu k výsledkům prostřednictvím vynést() nebo fetchAll () metody: použijete jej pro příkaz, který nemění tabulku, například VYBRAT.
Ten místo toho vrací počet řádků, které byly změněny dotazem: používáme to pro příkazy, které upravují řádky, jako VLOŽIT, VYMAZAT nebo AKTUALIZACE. Přímé příkazy se mají používat pouze v případě, že v dotazu nejsou žádné proměnné a vy absolutně věříte, že je bezpečný a správně unikl.

Připravená prohlášení

PDO podporuje také dvoustupňové připravené příkazy: to je užitečné při použití proměnných v dotazu a je obecně bezpečnější, protože připravit() metoda provede všechny potřebné úniky za nás. Podívejme se, jak se proměnné používají. Představte si, že chceme vložit vlastnosti objektu Planet do Planety stůl. Nejprve bychom připravili dotaz:
$ stmt = $ pdo-> připravit ("INSERT INTO planet (name, color) VALUES (?,?)"); 
Jak již bylo řečeno, nejprve použijeme připravit() metoda, která bere dotaz sql jako argument, pomocí zástupných symbolů pro proměnné. Zástupné symboly nyní mohou být dvou typů:

Poziční zástupné symboly

Při použití ? poziční zástupné symboly můžeme získat stručnější kód, ale musíme poskytnout hodnoty, které mají být nahrazeny ve stejném pořadí názvů sloupců, v poli poskytnutém jako argument vykonat() metoda:

$ stmt-> execute ([$ planet-> name, $ planet-> color]); 

Pojmenované zástupné symboly

Použitím pojmenované zástupné symboly, nemusíme respektovat konkrétní objednávku, ale vytvoříme podrobnější kód. Při provádění vykonat() metoda bychom měli poskytnout hodnoty ve formě asociativní pole ve kterém by každý klíč byl jménem použitého zástupného symbolu a přidružená hodnota by byla ta, která má být v dotazu nahrazena. Například výše uvedený dotaz by se stal:

$ stmt = $ pdo-> připravit ("INSERT INTO planet (name, color) VALUES (: name,: color)"); $ stmt-> execute (['name' => $ planet-> name, 'color' => $ planet-> color]); 
Metody přípravy a spuštění lze použít jak při provádění dotazů, které upravují, nebo jen načítají data z databáze. V prvním případě použijeme k načtení dat metody načítání, které jsme viděli výše, zatímco v druhém případě můžeme načíst počet ovlivněných řádků pomocí rowCount () metoda.

Metody bindValue () a bindParam ()

K zadání hodnot, které mají být v dotazu nahrazeny, můžeme také použít bindValue () a bindParam () metody. První váže hodnotu poskytnuté proměnné na související poziční nebo pojmenovaný zástupný symbol použitý při přípravě dotazu. Pomocí výše uvedeného příkladu bychom udělali:
$ stmt-> bindValue ('name', $ planet-> name, PDO :: PARAM_STR); 
Vazíme na hodnotu $ planet-> jméno do :název zástupný symbol. Všimněte si, že pomocí metod bindValue () a bindParam () můžeme jako třetí argument určit typ proměnné, v tomto případě pomocí související konstanty CHOP PDO :: PARAM_STR.
Použitím bindParam (), místo toho můžeme proměnnou vázat na související zástupný symbol použitý při přípravě dotazu. Všimněte si, že v tomto případě je proměnná vázána odkaz, a jeho hodnota bude nahrazena zástupným symbolem pouze v době, kdy vykonat() metoda se tomu říká. Syntaxe je stejná jako výše:
$ stmt-> bindParam ('name', $ planet-> name, PDO :: PARAM_STR) 
Vázali jsme proměnnou $ planet-> name na :název zástupný symbol, nikoli jeho aktuální hodnota! Jak bylo řečeno výše, převod bude proveden právě v okamžiku, kdy vykonat() bude volána metoda, takže zástupný symbol bude nahrazen hodnotou, kterou má proměnná v té době.

Transakce CHOP

Transakce poskytují způsob, jak zachovat konzistenci při vydávání více dotazů. Všechny dotazy jsou prováděny v dávce a jsou zadány do databáze, pouze pokud jsou všechny úspěšné. Transakce nebudou fungovat ve všech databázích a ne ve všech sql konstrukce, protože některé z nich způsobují a implicitní potvrzení (úplný seznam zde)
V extrémním a podivném příkladu si představte, že uživatel musí vybrat seznam planet a pokaždé, když odešle nový výběr, chcete odstranit předchozí z databáze před vložením nové. Co by se stalo, kdyby vymazání proběhlo úspěšně, ale ne vložení? Měli bychom uživatele bez planet! Takto se obvykle provádějí transakce:
$ pdo-> beginTransaction (); zkuste $ stmt1 = $ pdo-> exec ("ODSTRANIT Z planet"); $ stmt2 = $ pdo-> připravit ("INSERT INTO planet (name, color) VALUES (?,?)"); foreach ($ planety jako $ planet) $ stmt2-> execute ([$ planet-> getName (), $ planet-> getColor ()]);  $ pdo-> commit ();  catch (PDOException $ e) $ pdo-> rollBack (); 
Nejprve ze všech beginTransaction () Metoda objektu PDO zakáže autocommit dotazu, poté se uvnitř bloku try-catch spustí dotazy v požadovaném pořadí. V tomto okamžiku, pokud ne Výjimka PDO je vyvolána, dotazy jsou potvrzeny pomocí spáchat() metoda, jinak prostřednictvím rollBack () způsob, transakce se vrátí a obnoví se automatický příkaz.
Tímto způsobem bude při vydávání více dotazů vždy konzistence. Je zcela zřejmé, že transakce PDO můžete používat, pouze když PDO :: ATTR_ERRMODE je nastaven na PDO :: ERRMODE_EXCEPTION.



Zatím žádné komentáře

Sbírka užitečných informací o operačním systému Linux a nových technologiích
Nejnovější články, praktické tipy, podrobné recenze a průvodci. Ve světě operačního systému Linux se budete cítit jako doma