Pdo php skript se provede 2x. PHP PDO - správná práce s databázemi



příklad klíčových slov meta tag (4)

cílová

Jak vidím, váš cíl je v tomto případě dvojí:

  • vytvořit a udržovat jediné/opakovaně použitelné připojení pro každou databázi
  • ujistěte se, že je připojení správně nakonfigurováno

Řešení

$provider = function() ( $instance = new PDO("mysql:......;charset=utf8", "username", "password"); $instance->setAttribute(PDO::ATTR_ERRMODE, PDO: :ERRMODE_EXCEPTION); $instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); return $instance; ); $factory = new StructureFactory($provider);

Poté v jiném souboru nebo níže ve stejném souboru:

$něco = $továrna->vytvořit("Něco"); $foobar = $factory->create("Foobar");

Samotná továrna by měla vypadat nějak takto:

Class StructureFactory ( protected $provider = null; protected $connection = null; veřejná funkce __construct(volatelný $provider) ( $this->provider = $provider; ) veřejná funkce create($name) ( if ($this->connection = == null) ( $this->connection = call_user_func($this->provider); ) vrátit nové $name($this->connection); ) )

Tímto způsobem můžete mít centralizovanou strukturu, která zajišťuje, že se připojení vytvoří pouze v případě potřeby. To by také usnadnilo proces testování a údržby jednotky.

Dodavatel v tomto případě bude nalezen někde během bootstrap fáze. Tento přístup také poskytne jasné místo, kde můžete definovat konfiguraci, kterou používáte pro připojení k DB.

Mějte na paměti, že toto extrémně zjednodušený příklad. Možná byste se také rádi podívali na následující dvě videa:

Také vřele doporučuji přečíst si řádný návod o používání PDO (online je špatný protokol výukového programu).

Čas od času vidím dotazy ohledně připojení k databázi.
Většina odpovědí není, jak to dělám já, nebo prostě neumím odpovědět správně. Tak jako tak; Nikdy jsem o tom nepřemýšlel, protože způsob, jakým to dělám, mi funguje.

Ale tady je bláznivá myšlenka; Možná to všechno dělám špatně, a pokud ano; Opravdu by mě zajímalo, jak se správně připojit k databázi Data MySQL pomocí PHP a PDO a zpřístupnit je.

Dělám to takto:

Za prvé, zde je moje struktura souborů (zkrácený) :

Public_html/ * index.php * initialize/ -- load.initialize.php -- configure.php -- sessions.php

index.php
Úplně nahoře požaduji("initialize/load.initialize.php"); ,

load.initialize.php

# konfigurace webu vyžadují("configure.php"); # připojení k databázi vyžaduje("root/somewhere/connect.php"); // tento soubor je pro lepší zabezpečení umístěn mimo public_html. # include class foreach (glob("assets/classes/*.class.php") jako $class_filename)( include($class_filename); ) # include functions foreach (glob("assets/functions/*.func.php") as $func_filename)( include($func_filename); ) # handle sessions required("sessions.php");

Vím, že existuje lepší nebo správnější způsob, jak zahrnout třídy, ale nepamatuji si, co to bylo. Ještě jsem neměl čas se na to podívat, ale myslím, že to bylo něco s automatickým načítáním. něco takového...

configure.php
Tady v podstatě jen některé přebíjím php.ini-vlastnosti a dělat některé další globální nastavení pro web

connect.php
Nastavil jsem připojení ke třídě tak, aby ostatní třídy mohly rozšířit tento...

Třída connect_pdo ( chráněné $dbh; veřejná funkce __construct() ( try ( $db_host = " "; // název hostitele $ název_db = " "; // název databáze $db_user = " "; // uživatelské jméno $user_pw = " "; // heslo $con = new PDO("mysql:host=".$db_host."; dbname=".$db_name, $db_user, $user_pw); $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $con->exec("SET CHARACTER SET utf8"); // vrátí všechny požadavky SQL jako UTF-8 ) catch (PDOException $err) ( echo "neškodná chybová zpráva, pokud se připojení nezdaří"; $err->getMessage() "
"; file_put_contents("PDOErrors.txt",$err, FILE_APPEND); // zapsat některé podrobnosti do protokolu chyb mimo public_html die(); // ukončit připojení ) ) veřejná funkce dbh() ( return $this->dbh ;) ) # vložte obsluhu databáze do var pro snazší přístup $con = new connect_pdo(); $con = $con->dbh(); //

To je místo, kde opravdu věřím, že existuje prostor pro masivní zlepšení, protože jsem se nedávno začal učit OOP a místo mysql používám PDO.
Tak jsem jen sledoval pár tutoriálů pro začátečníky a vyzkoušel různé věci...

sessions.php
Kromě zpracování normálních relací také inicializuji některé třídy v relaci takto:

If (!isset($_SESSION["sqlQuery"]))( session_start(); $_SESSION["sqlQuery"] = new sqlQuery(); )

Takže tato třída je dostupná všude. To nemusí být moc dobrý trénink (?) ...
Každopádně toto mi tento přístup umožňuje dělat všude:

Echo $_SESSION["sqlQuery"]->getAreaName("kraj",9); // výstupy: Aust-Agder (název okresu s tímto ID v databázi)

Uvnitř mého třída sqlQuery, který rozšiřuje můj Třída connect_pdo , mám veřejnou funkci getAreaName, která zpracovává dotaz v mé databázi.
Myslím, že docela slušné.

Funguje jako kouzlo
Takže v podstatě to dělám já.
Také, kdykoli potřebuji načíst něco z mé DB z třídy, udělám něco podobného:

$id = 123; $sql = "VYBERTE cokoliv Z MyTable WHERE id = :id"; $qry = $con->prepare($sql); $qry -> bindParam(":id", $id, PDO::PARAM_INT); $qry -> vykonat(); $get = $qry->fetch(PDO::FETCH_ASSOC);

Protože spojení vkládám do proměnné uvnitř connect_pdo.php, jen na to odkazuji a můžu jít. Funguje to. Dostávám očekávané výsledky...

Ale bez ohledu na to; Opravdu bych ocenil, kdybyste mi řekli, jestli odsud odejdu. Místo toho bych musel změnit oblasti, které bych mohl nebo měl změnit pro zlepšení atd...

Opravdu chci studovat...

$dsn = "mysql:host=název_vašeho_hostitele;dbname=název_vaše_db_zde"; // definovat název hostitele a název databáze $username = "vy"; // definujte uživatelské jméno $pwd="vaše_heslo"; // zkuste heslo ( $db = nové PDO($dsn, $username, $pwd); ) catch (PDOException $e) ( $error_message = $e->getMessage(); echo "toto se zobrazuje, protože byla nalezena chyba "; exit(); )

Nedávno jsem na podobnou odpověď/otázku přišel sám. Udělal jsem toto, kdyby to někoho zajímalo:

args = func_get_args(); ) veřejná funkce __call($method, $args) ( if (empty($this->db)) ( $Ref = new \ReflectionClass("\PDO"); $this->db = $Ref->newInstanceArgs($ this->args); ) return call_user_func_array(pole($this->db, $method), $args); ) )

Chcete-li to zavolat, stačí změnit tento řádek:

$DB = new \Library\PDO(/* normální argumenty */);

A typ nápovědy, pokud ji používáte (\Library\PDO$DB).

To je skutečně podobné přijaté odpovědi a vaší; má však značnou výhodu. Zvažte tento kód:

$DB = new \Library\PDO(/* args */); $STH = $DB->prepare("SELECT * FROM users WHERE user = ?"); $STH->execute(pole(25)); $User = $STH->fetch();

I když to může vypadat jako běžné PDO (je upraveno pouze touto \Library\), ve skutečnosti neinicializuje objekt, dokud nezavoláte první metodu, ať už to je kterákoli. Díky tomu je optimalizován, protože vytvoření objektu PDO je trochu drahé. Toto je transparentní třída, nebo jak se tomu říká Ghost, forma. Můžete zacházet s $DB jako s běžnou instancí PDO, předávat ji, provádět stejné operace atd.

Doporučuji nepoužívat $_SESSION pro globální přístup k vašemu DB připojení.

Můžete udělat jednu z několika věcí (dobře nejhorší za nejlepší praktik):

  • Přístup k $dbh pomocí globálního $dbh uvnitř vašich funkcí a tříd
  • Použijte singletonový registr a přistupujte k němu globálně, například:

    $registry = MyRegistry::getInstance(); $dbh = $registr->getDbh();

    Přidejte obslužnou rutinu databáze do tříd, které potřebuje:

    Třída MyClass ( veřejná funkce __construct($dbh) ( /* ... */ ) )

Je však trochu pokročilejší a vyžaduje více „drátování“ bez rámu. Pokud je tedy pro vás vkládání závislostí příliš složité, použijte místo kolekce globálních proměnných registr singleton.

Poskytuje metody pro přípravu výrazů a práci s objekty, které vám mohou zvýšit produktivitu!

Úvod do CHOP

"PDO - PHP Data Objects je vrstva pro přístup k databázi, která poskytuje jednotné metody pro přístup k různým databázím."

Nespoléhá se na specifickou syntaxi databáze a umožňuje vám ve většině případů snadno přejít na jiný typ databáze a platformu jednoduše změnou připojovacího řetězce.

Tato lekce není popisem procesu práce s SQL. Je určen pro ty, kteří používají rozšíření mysql nebo mysqli pomoci jim přejít na výkonnější a přenosnější CHOP.

Podpora databáze

Rozšíření podporuje jakoukoli databázi, pro kterou existuje ovladač PDO. V současné době jsou k dispozici ovladače pro následující typy databází:

  • PDO_DBLIB (FreeTDS / Microsoft SQL Server / Sybase)
  • PDO_FIREBIRD (Firebird/Interbase 6)
  • PDO_IBM (IBM DB2)
  • PDO_INFORMIX (IBM Informix Dynamic Server)
  • PDO_MYSQL (MySQL 3.x/4.x/5.x)
  • PDO_OCI (rozhraní volání Oracle)
  • PDO_ODBC (ODBC v3 (IBM DB2, unixODBC a win32 ODBC))
  • PDO_PGSQL (PostgreSQL)
  • PDO_SQLITE (SQLite 3 a SQLite 2)
  • PDO_4D (4D)

Aby systém fungoval, stačí nainstalovat pouze ty ovladače, které jsou skutečně potřeba. Seznam ovladačů dostupných v systému můžete získat takto:

Print_r(PDO::getAvailableDrivers());

Spojení

Různé databáze mohou mít mírně odlišné způsoby připojení. Níže jsou uvedeny způsoby připojení k několika populárním databázím. Všimnete si, že první tři jsou navzájem totožné a pouze SQLite má specifickou syntaxi.


zkuste ( # MS SQL Server a Sybase s PDO_DBLIB $DBH = nové PDO("mssql:host=$host;dbname=$dbname, $user, $pass"); $DBH = nový PDO("sybase:host=$hostitel ;dbname=$dbname, $user, $pass"); # MySQL s PDO_MYSQL $DBH = nové PDO("mysql:host=$host;dbname=$dbname", $user, $pass); # SQLite $DBH = new PDO("sqlite:my/database/path/database.db"); ) catch (PDOException $e) ( echo $e->getMessage(); )

Věnujte pozornost bloku Zkus chytit- operace PDO byste měli vždy zabalit do bloku Zkus chytit a použijte mechanismus výjimek. Obvykle se vytvoří pouze jedno připojení, náš příklad ukazuje více připojení, aby byla ukázána syntaxe. $DBH obsahuje popisovač databáze a bude používán v celém našem tutoriálu.

Jakékoli připojení můžete ukončit nastavením rukojeti na nula.

# Uzavřete spojení $DBH = null;

Více o konkrétních možnostech a připojovacích řetězcích pro různé databáze se můžete dozvědět z dokumentů na PHP.net.

Výjimky a CHOP

PDO může používat výjimky ke zpracování chyb. To znamená, že všechny operace PDO musí být uzavřeny do bloku Zkus chytit. PDO může vyvolat tři úrovně chyb, úroveň kontroly chyb se vybírá nastavením atributu režimu kontroly chyb pro deskriptor databáze:

$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Bez ohledu na nastavenou úroveň řízení chyba připojení vždy vyvolá výjimku, a proto by měla být vždy uzavřena v bloku Zkus chytit.

PDO::ERRMODE_SILENT

Úroveň kontroly chyb je standardně nastavena. Na této úrovni se chyby generují podle stejného principu jako v rozšířeních mysql nebo mysqli. Další dvě úrovně kontroly chyb jsou vhodnější pro programovací styl DRY (Don't Repeat Youself).

PDO::ERRMODE_WARNING

Na této úrovni kontroly chyb jsou generována standardní PHP varování a program může pokračovat ve vykonávání. Tato úroveň je vhodná pro ladění.

PDO::ERRMODE_EXCEPTION

Tato úroveň kontroly chyb by se měla používat ve většině situací. Výjimky jsou generovány za účelem pečlivého zpracování chyb a skrytí dat, která by mohla někomu pomoci hacknout váš systém. Níže je uveden příklad demonstrující výhody výjimek:

# Zkuste se připojit k databázi ( $DBH = nový PDO("mysql:host=$host;dbname=$dbname", $user, $pass); $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) ; # Chybné zadání DELECT místo SELECT! $DBH->prepare("DELECT name FROM people"); ) catch(PDOException $e) ( echo "Omlouváme se. Ale operaci nelze provést."; file_put_contents("PDOErrors. txt" , $e->getMessage(), FILE_APPEND); )

Zde je záměrná chyba v příkazu SELECT. To vyvolá výjimku. Výjimka odešle popis chyby do souboru protokolu a zobrazí zprávu uživateli.

Vkládání a aktualizace dat

Vkládání nových dat nebo aktualizace stávajících dat je jednou z nejčastěji používaných běžných databázových operací. Při použití PDO se rozkládá na dvě fáze. Vše popsané v této kapitole platí pro obě operace. AKTUALIZACE A VLOŽIT.


Zde je příklad nejpoužívanějšího typu vkládání dat:

# STH je "stavový ovladač" $STH = $DBH->prepare("INSERT INTO people (first_name) values ​​​​("Cathy")"); $STH->execute();

Tuto operaci můžete samozřejmě provést pomocí metody exec() a počet hovorů bude o jedno méně. Pro získání výhod připravených výrazů je ale lepší použít delší metodu. I když je zamýšlíte použít pouze jednou, připravené výrazy vám pomohou chránit se před útoky na váš systém.

Připravené výrazy

Připravené příkazy jsou předkompilované příkazy SQL, které lze provést mnohokrát odesláním pouze dat na server. Další výhodou je automatické naplnění šablony daty v podobě ochrany před útoky prostřednictvím příloh SQL kódu.

Připravené výrazy můžete použít zahrnutím šablon do kódu SQL. Níže jsou uvedeny 3 příklady: jeden bez šablon, jeden s nepojmenovanými šablonami, jeden s pojmenovanými šablonami.

# žádné šablony – otevřené útokům SQL injection! $STH = $DBH->("INSERT INTO people (name, addr, city) values ​​​​($name, $addr, $city)"); # nepojmenovaných šablon $STH = $DBH->("INSERT INTO lidí (jméno, adresa, město) hodnoty ​​(?, ?, ?); # pojmenovaných šablon $STH = $DBH->("INSERT INTO lidí (jméno , addr , city) value (:name, :addr, :city)");

Měli byste se vyhnout použití první metody. Výběr pojmenovaných nebo nepojmenovaných vzorů ovlivňuje, jak nastavíte data pro tyto výrazy.

Nepojmenované šablony

# ke každé šabloně přiřaďte proměnné, indexované od 1 do 3 $STH->bindParam(1, $name); $STH->bindParam(2, $addr); $STH->bindParam(3, $město); # Vložte jeden řádek $name = "Dima" $addr = "Lizyukova St."; $city = "Moskva"; $STH->execute(); # Vložit další řádek $name = "Senya" $addr = "Komunistická slepá ulička"; $city = "Petr"; $STH->execute();

Operace probíhá ve dvou fázích. V prvním kroku jsou šablonám přiřazeny proměnné. Poté jsou proměnným přiřazeny hodnoty a výraz je proveden. Chcete-li odeslat další část dat, musíte změnit hodnoty proměnných a znovu spustit výraz.

Vypadá to trochu těžkopádně pro výrazy se spoustou parametrů? Rozhodně. Pokud jsou však vaše data uložena v poli, bude vše velmi krátké:

# Data k vložení $data = array("Monya", "Forget-Me-Not Avenue", "Zakutajsk"); $STH = $DBH->("INSERT INTO people (jméno, adresa, město) hodnoty ​​(?, ?, ?)"); $STH->execute($data);

Data v poli jsou nahrazena do šablon v pořadí, v jakém se objevují. $data jde do první šablony, $data do druhé a tak dále. Pokud je však pole indexováno v jiném pořadí, nebude taková operace provedena správně. Musíte zajistit, aby pořadí vzorů odpovídalo pořadí dat v poli.

Pojmenované šablony

Zde je příklad použití pojmenované šablony:

# První argument funkce je název pojmenované šablony # Pojmenovaná šablona vždy začíná dvojtečkou $STH->bindParam(":name", $name);

Můžete použít zkratky, ale fungují s přidruženými poli. Příklad:

# Data k vložení $data = array("name" => "Michelle", "addr" => "Kuznechny Lane", "city" => "Cnjkbwf"); # Zkratka $STH = $DBH->("INSERT INTO people (name, addr, city) value (:name, :addr, :city)"); $STH->execute($data);

Klíče vaší tabulky nevyžadují dvojtečku, ale přesto musí odpovídat názvům šablon. Pokud používáte pole polí, můžete je iterovat a jednoduše zavolat vykonat pro každý soubor dat.

Další příjemnou vlastností pojmenovaných šablon je možnost vkládat objekty přímo do databáze, když se vlastnosti a názvy polí shodují. Příklad:

# Simple object class person ( public $name; public $addr; public $city; function __construct($n,$a,$c) ( $this->name = $n; $this->addr = $a; $ this->city = $c; ) # atd... ) $cathy = new person("Katya","Lenin Avenue","Mozhaisk"); # Proveďte: $STH = $DBH->("INSERT INTO people (name, addr, city) value (:name, :addr, :city)"); $STH->execute((pole)$cathy);

Převod typu objektu na pole PROTI vykonat způsobí, že vlastnosti budou považovány za klíče pole.

Přijímání dat


K získávání dat se používá metoda identifikátoru stavu ->fetch(). Před voláním metody vynést() musíte PDO sdělit, jak budete získávat data z databáze. Můžete vybrat následující možnosti:

  • PDO::FETCH_ASSOC: vrátí pole indexované podle názvů sloupců
  • PDO::FETCH_BOTH (výchozí): vrátí pole indexované podle názvů sloupců a čísel
  • PDO::FETCH_BOUND: Přiřadí hodnoty vašich sloupců sadě proměnných pomocí metody ->bindColumn()
  • PDO::FETCH_CLASS: přiřadí hodnoty sloupců vlastnostem pojmenované třídy; pokud odpovídající vlastnost neexistuje, je vytvořena
  • PDO::FETCH_INTO: aktualizuje existující instanci pojmenované třídy
  • PDO::FETCH_LAZY: kombinace PDO::FETCH_BOTH/PDO::FETCH_OBJ, vytváří názvy proměnných objektů tak, jak jsou používány
  • PDO::FETCH_NUM: vrátí pole indexované podle čísel sloupců
  • PDO::FETCH_OBJ: vrací anonymní objekt s názvy vlastností odpovídajícími názvům sloupců

Ve skutečnosti se základní situace řeší pomocí tří možností: FETCH_ASSOC, FETCH_CLASS A FETCH_OBJ. Postup nastavení metody extrakce dat:

$STH->setFetchMode(PDO::FETCH_ASSOC);

Přímo ve volání metody můžete také nastavit metodu načítání dat ->fetch().

FETCH_ASSOC

Tento typ načítání dat vytváří asociativní pole indexované podle názvů sloupců. Mělo by to být poměrně dobře známé těm, kteří používají rozšíření mysql/mysqli. Ukázka dat:

$STH = $DBH->query("VYBRAT jméno, adr, město od lidí"); # Nastavte režim získávání dat $STH->setFetchMode(PDO::FETCH_ASSOC); while($row = $STH->fetch()) ( echo $row["name"] . "\n"; echo $row["addr"] . "\n"; echo $row["city"] . "\n" ;)

Cyklus zatímco pokračuje v iteraci výsledku vzorku jeden řádek po druhém, dokud nebude dokončen.

FETCH_OBJ

S tímto typem načítání dat je vytvořen objekt třídy std pro každý řádek přijatých dat:

$STH = $DBH->query("VYBRAT jméno, adr, město od lidí"); # Nastavte režim načítání dat $STH->setFetchMode(PDO::FETCH_OBJ); # zobrazit výsledek while($row = $STH->fetch()) ( echo $row->name . "\n"; echo $row->addr. "\n"; echo $row->city ." \ n" ;)

FETCH_CLASS

Při tomto typu extrakce jsou data umístěna přímo do třídy, kterou si vyberete. Použitím FETCH_CLASS vlastnosti vašeho objektu jsou nastaveny PŘED voláním konstruktoru. Je to velmi důležité. Pokud vlastnost odpovídající názvu sloupce neexistuje, bude taková vlastnost vytvořena (jako veřejnost) pro tebe.

To znamená, že pokud data potřebují transformaci po načtení z databáze, může to být provedeno automaticky vaším objektem, jakmile je vytvořeno.

Představte si například situaci, kdy musí být adresa u každého záznamu částečně skryta. Úkol můžeme splnit manipulací s vlastností v konstruktoru:

Tajná_osoba třídy ( public $name; public $addr; public $city; public $other_data; function __construct($other = "") ( $this->address = preg_replace("//", "x", $this-> adresa); $this->other_data = $other; ))

Jakmile jsou data extrahována do třídy, všechna malá písmena a–z v adrese budou nahrazena znakem x. Nyní, pomocí třídy a načítání dat, transformace probíhá zcela transparentně:

$STH = $DBH->query("VYBRAT jméno, adr, město od lidí"); $STH->setFetchMode(PDO::FETCH_CLASS, "tajná_osoba"); while($obj = $STH->fetch()) ( echo $obj->addr; )

Pokud byla adresa 'Leninsky Prospekt 5', uvidíte 'Lxxxxxxxxxx xx-x 5'. Samozřejmě existují situace, kdy chcete, aby byl konstruktor zavolán před přiřazením dat. PDO má prostředky k realizaci:

$STH->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "tajná_osoba");

Nyní, když zopakujete předchozí příklad s nastaveným režimem PDO::FETCH_PROPS_LATE adresa nebude skryta, protože byl zavolán konstruktor a byly přiřazeny vlastnosti.

Pokud potřebujete, můžete při extrahování dat do objektu předat konstruktoru argumenty:

$STH->setFetchMode(PDO::FETCH_CLASS, "tajná_osoba", array("stuff"));

Pokud potřebujete pro každý objekt předat konstruktoru jiná data, můžete uvnitř metody nastavit režim načítání dat vynést:

$i = 0; while($rowObj = $STH->fetch(PDO::FETCH_CLASS, "secret_person", array($i))) ( // dělat věci $i++ )

Některé další užitečné metody

Protože PDO nelze v krátkém článku plně popsat, představíme několik užitečných metod pro provádění základních operací.

$DBH->lastInsertId();

Metoda ->lastInsertId() je vždy volána popisovačem databáze (nikoli popisovačem stavu) a vrací hodnotu automaticky inkrementovaného id posledního vloženého řádku pro dané připojení.

$DBH->exec("SMAZAT OD lidí, KDE 1"); $DBH->exec("SET time_zone = "-8:00"");

Metoda ->exec() používá se pro různé pomocné operace.

$safe = $DBH->quote($unsafe);

Metoda ->citovat() kvóty řetězce, takže je lze použít v dotazech. Toto je vaše rezerva pro případ, že nebudou použity připravené výrazy.

$rows_affected = $STH->rowCount();

Metoda ->rowCount() vrací hodnotu celé číslo, udávající počet řádků, které jsou zpracovány operací. V nejnovější verzi PDO podle zprávy o chybě (http://bugs.php.net/40822) tato metoda nefunguje s výrazy VYBRAT. Pokud máte problémy a nemůžete aktualizovat PHP, můžete získat počet řádků následujícím způsobem:

$sql = "VYBRAT POČET(*) OD lidí"; if ($STH = $DBH->query($sql)) ( # Zkontrolujte počet řádků if ($STH->fetchColumn() > 0) ( # Zde by měl být kód SELECT) else ( echo "Existují žádné řádky neodpovídají dotazu." ;))

Doufám, že se vám lekce líbila!

Nastavení a používání PDO - rozšíření PHP Data Objects pro práci s databázemi

Vytvoření testovací databáze a tabulky

Nejprve vytvořte databázi pro tento tutoriál:

CREATE DATABASE solar_system; UDĚLEJTE VŠECHNA PRIVILEGIA NA solar_system.* "testuser"@"localhost" IDENTIFIKUJE "testpassword";

Uživateli s přihlašovacím jménem testuser a heslem testpassword byla udělena plná přístupová práva k databázi solar_system.

Nyní vytvoříme tabulku a naplníme ji daty, jejichž astronomická přesnost není zahrnuta:

USE solar_system; CREATE TABLE planety (id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), název VARCHAR(10) NOT NULL, barva VARCHAR(10) NOT NULL); INSERT INTO planet(jméno, barva) VALUES("země", "modrá"), ("mars", "červená"), ("jupiter", "divný");

Popis připojení

Nyní, když je databáze vytvořena, pojďme definovat DSN () - informace pro připojení k databázi, prezentované jako řetězec. Syntaxe popisu se liší v závislosti na použitém DBMS. V příkladu pracujeme s MySQL/MariaDB, takže uvádíme:

  • jméno hostitele, kde se nachází DBMS;
  • port (volitelný, pokud je použit standardní port 3306);
  • jméno databáze;
  • kódování (volitelné).

Linka DSN v tomto případě vypadá takto:

$dsn = "mysql:host=localhost;port=3306;dbname=solar_system;charset=utf8";

Předpona databáze je specifikována jako první. V příkladu - mysql. Předpona je oddělena od zbytku řádku dvojtečkou a každý následující parametr je oddělen středníkem.

Vytvoření objektu PDO

Nyní, když je řetězec DSN připraven, vytvoříme objekt PDO. Vstupní konstruktor přijímá následující parametry:

  1. DSN řetězec.
  2. Jméno uživatele, který má přístup k databázi.
  3. Heslo tohoto uživatele.
  4. Pole s dalšími parametry (volitelné).
$options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; $pdo = nové PDO($dsn, "testuser", "testpassword", $options);

Další parametry lze také definovat po vytvoření objektu pomocí metody SetAttribute:

$pdo->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Definování výchozí metody vzorkování

PDO::DEFAULT_FETCH_MODE je důležitý parametr, který určuje výchozí metodu načítání. Uvedená metoda se používá při získávání výsledku požadavku.

PDO::FETCH_BOTH

Výchozí režim. Výsledek výběru je indexován jak čísly (od 0), tak názvy sloupců:

$stmt = $pdo->query("SELECT * FROM planet"); $results = $stmt->fetch(PDO::FETCH_BOTH);

Po provedení dotazu s tímto režimem proti testovací tabulce planet získáme následující výsledek:

Pole ( => 1 => 1 => země => země => modrá => modrá)

PDO::FETCH_ASSOC

Výsledek je uložen v asociativním poli, ve kterém je klíčem název sloupce a hodnota je odpovídající hodnota řádku:

$stmt = $pdo->query("SELECT * FROM planet"); $results = $stmt->fetch(PDO::FETCH_ASSOC);

V důsledku toho dostaneme:

Pole ( => 1 => země => modrá)

PDO::FETCH_NUM

Při použití tohoto režimu je výsledek prezentován jako pole indexované čísly sloupců (počínaje 0):

Pole ( => 1 => země => modrá)

PDO::FETCH_COLUMN

Tato možnost je užitečná, pokud potřebujete získat seznam hodnot pro jedno pole ve formě jednorozměrného pole, jehož číslování začíná od 0. Například:

$stmt = $pdo->query("VYBRAT jméno FROM planet");

V důsledku toho dostaneme:

Array ( => Země => Mars => Jupiter)

PDO::FETCH_KEY_PAIR

Tuto možnost používáme, pokud potřebujeme získat seznam hodnot dvou polí ve formě asociativního pole. Klíče pole jsou data v prvním sloupci výběru, hodnoty pole jsou data ve druhém sloupci. Například:

$stmt = $pdo->query("VYBRAT jméno, barvu FROM planet"); $result = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);

V důsledku toho dostaneme:

Pole ( => modrá => červená => divná)

PDO::FETCH_OBJECT

Při použití PDO::FETCH_OBJECT se pro každý načtený řádek vytvoří anonymní objekt. Jeho veřejnými vlastnostmi jsou názvy vzorových sloupců a jako jejich hodnoty se používají výsledky dotazu:

$stmt = $pdo->query("VYBRAT jméno, barvu FROM planet"); $results = $stmt->fetch(PDO::FETCH_OBJ);

V důsledku toho dostaneme:

Objekt StdClass ( => země => modrá)

PDO::FETCH_CLASS

V tomto případě, stejně jako v předchozím, se hodnoty sloupců stanou vlastnostmi objektu. Musíte však zadat existující třídu, která bude použita k vytvoření objektu. Podívejme se na to na příkladu. Nejprve vytvoříme třídu:

Třída Planet ( private $name; private $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; ) )

Vezměte prosím na vědomí, že třída Planet má soukromé vlastnosti a nemá konstruktor. Nyní provedeme požadavek.

Pokud používáte metodu načtení s PDO::FETCH_CLASS , musíte před odesláním požadavku na načtení dat použít metodu setFetchMode:

$stmt = $pdo->query("VYBRAT jméno, barvu FROM planet"); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planeta");

První parametr, který předáme metodě setFetchMode, je konstanta PDO::FETCH_CLASS. Druhý parametr je název třídy, která bude použita při vytváření objektu. Nyní udělejme:

$planeta = $stmt->fetch(); var_dump($planeta);

V důsledku toho dostaneme objekt Planet:

Planeta Objekt ( => Země => modrá)

Hodnoty vrácené dotazem jsou přiřazeny odpovídajícím vlastnostem objektu, dokonce i soukromým.

Definování vlastností po provedení konstruktoru

Třída Planet nemá explicitní konstruktor, takže při přiřazování vlastností nebudou žádné problémy. Pokud má třída konstruktor, ve kterém byla vlastnost přiřazena nebo změněna, budou přepsány.

Při použití konstanty FETCH_PROPS_LATE budou hodnoty vlastností přiřazeny po provedení konstruktoru:

Třída Planet ( private $name; private $color; public function __construct($name = měsíc, $color = šedá) ( $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() (vrátit $this->color; ) )

Upravili jsme třídu Planet přidáním konstruktoru, který má jako vstup dva argumenty: název a barvu. Výchozí hodnoty pro tato pole jsou měsíc a šedá.

Pokud nepoužijete FETCH_PROPS_LATE, vlastnosti budou při vytvoření objektu přepsány výchozími hodnotami. Pojďme to zkontrolovat. Nejprve spusťte dotaz:

$stmt = $pdo->query("SELECT jméno, barvu FROM solar_system WHERE name = "země""); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planeta"); $planeta = $stmt->fetch(); var_dump($planeta);

V důsledku toho dostaneme:

Object(Planet)#2 (2) ( ["name":"Planet":private]=> string(4) "moon" ["color":"Planet":private]=> string(4) "grey" )

Podle očekávání jsou hodnoty načtené z databáze přepsány. Nyní se podívejme na řešení problému pomocí FETCH_PROPS_LATE (podobný požadavek):

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planeta"); $planeta = $stmt->fetch(); var_dump($planeta);

V důsledku toho dostaneme to, co potřebujeme:

Object(Planet)#4 (2) ( ["name":"Planet":private]=> string(5) "země" ["color":"Planet":private]=> string(4) "modrá" )

Pokud konstruktor třídy nemá výchozí hodnoty a jsou potřeba, nastaví se parametry konstruktoru při volání metody setFetchMode s třetím argumentem ve formě pole. Například:

Planeta třídy ( private $name; private $color; public function __construct($name, $color) ( $this->name = $name; $this->color = $color; ) [...] )

Argumenty konstruktoru jsou povinné, takže udělejme:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planeta", ["měsíc", "šedá"]);

Příchozí parametry také fungují jako výchozí hodnoty, které jsou potřebné pro inicializaci. V budoucnu budou přepsány hodnotami z databáze.

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

Více výsledků je načteno jako objekty pomocí metody načtení uvnitř smyčky while:

Zatímco ($planet = $stmt->fetch()) ( // zpracování výsledků )

Nebo vzorkováním všech výsledků najednou. Ve druhém případě se použije metoda fetchAll a režim je zadán v okamžiku volání:

$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, "Planeta", ["měsíc", "šedá"]);

PDO::FETCH_INTO

Když je vybrána tato možnost výběru, PDO nevytvoří nový objekt, ale aktualizuje vlastnosti stávajícího objektu. To je však možné pouze pro veřejné vlastnosti nebo při použití metody __set magic na objektu.

Připravené a přímé požadavky

Existují dva způsoby, jak provádět dotazy v PDO:

  • rovný, který se skládá z jednoho kroku;
  • připravený, který se skládá ze dvou kroků.

Přímé požadavky

Existují dva způsoby provádění přímých dotazů:

  • dotaz se používá pro příkazy, které neprovádějí změny, jako je SELECT. Vrátí objekt PDOStatemnt, ze kterého jsou načteny výsledky dotazu pomocí metod fetch nebo fetchAll;
  • exec se používá pro příkazy jako INSERT, DELETE nebo UPDATE. Vrátí počet řádků zpracovaných požadavkem.

Přímé operátory se používají pouze v případě, že v dotazu nejsou žádné proměnné a jste si jisti, že je dotaz bezpečný a správně escapovaný.

Připravené dotazy

PDO podporuje připravené příkazy, které jsou užitečné pro ochranu aplikace před: metoda Prepare provede nezbytné escapování.

Podívejme se na příklad. Chcete vložit vlastnosti objektu Planet do tabulky Planet. Nejprve si připravíme žádost:

$stmt = $pdo->prepare("INSERT INTO planet(name, color) VALUES(?, ?)");

Využíváme metodu Prepare, která jako argument bere SQL dotaz s pseudoproměnnými (placeholdery). Pseudovariable mohou být dvou typů: nepojmenované a pojmenované.

Nepojmenované pseudo proměnné

Nepojmenované pseudoproměnné (poziční zástupné symboly) jsou označeny ? . Výsledný dotaz je kompaktní, ale vyžaduje, aby byly hodnoty nahrazeny ve stejném pořadí. Jsou předávány jako pole metodou provádění:

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

Pojmenované Pseudoproměnné

Při použití pojmenovaných zástupných symbolů není důležité pořadí, ve kterém jsou hodnoty předány pro nahrazení, ale kód se v tomto případě stává méně kompaktní. Data jsou předávána metodě execute ve formě asociativního pole, ve kterém každý klíč odpovídá názvu pseudoproměnné a hodnota pole odpovídá hodnotě, kterou je třeba do požadavku dosadit. Zopakujme předchozí příklad:

$stmt = $pdo->prepare("INSERT INTO planet(name, color) VALUES(:name, :color)"); $stmt->execute(["name" => $planet->name, "color" => $planet->color]);

Metody přípravy a spouštění se používají jak při provádění požadavků na změnu, tak při načítání.

A informaci o počtu zpracovaných řádků v případě potřeby poskytne metoda rowCount.

Řízení chybového chování PDO

Parametr výběru chybového režimu PDO::ATTR_ERRMODE se používá k určení, jak se PDO chová v případě chyb. K dispozici jsou tři možnosti: PDO::ERRMODE_SILENT , PDO::ERRMODE_EXCEPTION a PDO::ERRMODE_WARNING .

PDO::ERRMODE_SILENT

Výchozí možnost. PDO jednoduše zaznamená informaci o chybě, kterou vám pomohou získat metody errorCode a errorInfo.

PDO::ERRMODE_EXCEPTION

Toto je preferovaná možnost, kdy PDO vyvolá kromě informací o chybě výjimku (PDOException). Výjimka přeruší provádění skriptu, což je užitečné při použití transakcí PDO. Příklad je uveden v popisu transakcí.

PDO::ERRMODE_WARNING

V tomto případě PDO zaznamená také informace o chybě. Tok skriptu není přerušen, ale jsou vydávána varování.

metody bindValue a bindParam

K nahrazení hodnot v dotazu můžete také použít metody bindValue a bindParam. První spojuje hodnotu proměnné s pseudoproměnnou, která se používá k přípravě požadavku:

$stmt = $pdo->prepare("INSERT INTO planet(name, color) VALUES(:name, :color)"); $stmt->bindValue("name", $planet->name, PDO::PARAM_STR);

Propojil hodnotu proměnné $planet->name s pseudoproměnnou:jméno . Všimněte si, že při použití metod bindValue a bindParam je typ proměnné zadán jako třetí argument pomocí příslušných konstant PDO. V příkladu - PDO::PARAM_STR .

Metoda bindParam váže proměnnou k pseudo proměnné. V tomto případě je proměnná spojena s odkazem na pseudoproměnnou a hodnota bude vložena do požadavku až po zavolání metody execute. Podívejme se na příklad:

$stmt->bindParam("name", $planet->name, PDO::PARAM_STR);

Transakce v CHOP

Představme si neobvyklý příklad. Uživatel musí vybrat seznam planet a pokaždé, když je požadavek proveden, aktuální data jsou z databáze odstraněna a poté jsou vložena nová. Pokud po smazání dojde k chybě, další uživatel obdrží prázdný seznam. Abychom tomu zabránili, používáme transakce:

$pdo->beginTransaction(); zkuste ( $stmt1 = $pdo->exec("DELETE FROM planet"); $stmt2 = $pdo->prepare("INSERT INTO planet(name, color) VALUES (?, ?)"); foreach ($planets as $planet) ( $stmt2->execute([$planet->getName(), $planet->getColor()]); ) $pdo->commit(); ) catch (PDOException $e) ( $pdo-> vrátit zpět (); )

Metoda beginTransaction zakáže automatické provádění požadavků a uvnitř konstrukce try-catch jsou požadavky prováděny v požadovaném pořadí. Pokud nejsou vyvolány žádné výjimky PDO, budou požadavky dokončeny pomocí metody odevzdání. V opačném případě budou vráceny zpět pomocí metody vrácení zpět a automatické provádění dotazů bude obnoveno.

To vytvořilo konzistenci při provádění dotazu. Aby k tomu došlo, je zřejmé, že PDO::ATTR_ERRMODE musí být nastaveno na PDO::ERRMODE_EXCEPTION .

Závěr

Nyní, když byla popsána práce s PDO, povšimněme si jeho hlavních výhod:

  • s PDO je snadné přenést aplikaci do jiných DBMS;
  • Jsou podporovány všechny populární DBMS;
  • vestavěný systém správy chyb;
  • různé možnosti prezentace výsledků vzorků;
  • jsou podporovány připravené dotazy, které zkracují kód a činí jej odolným vůči SQL injections;
  • Jsou podporovány transakce, které pomáhají udržovat integritu dat a konzistenci dotazů, když uživatelé pracují paralelně.


3. června 2018 Andrej Černyšov Tutoriál překladu 2025 0

PDO je zkratka pro PHP Data Objects: jde o PHP rozšíření pro práci s databázemi pomocí objektů. Jedna z jeho výhod spočívá v tom, že není přímo vázán na konkrétní databázi: jeho rozhraní umožňuje přístup k několika různým prostředím, včetně: MySQL, SQLite, PostgreSQL, Microsoft SQL Server.

Tato příručka si klade za cíl poskytnout úplný přehled o PDO a provést čtenáře krok za krokem od vytvoření a připojení k databázi až po výběr nejvhodnějších metod vyhledávání, ukázat, jak vytvořit připravené dotazy a popsat možné chybové režimy.

Vytvoření testovací databáze a tabulky

Nejprve si vytvoříme databázi:

CREATE DATABASE solar_system; UDĚLEJTE VŠECHNA PRIVILEGIA NA solar_system.* "testuser"@"localhost" IDENTIFIKUJE "testpassword";

Uživateli testuser jsme udělili všechna oprávnění v databázi solar_system pomocí testpassword pro heslo. Nyní vytvoříme tabulku a naplníme ji několika informacemi:

USE solar_system; CREATE TABLE planety (id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), název VARCHAR(10) NOT NULL, barva VARCHAR(10) NOT NULL); INSERT INTO planet(jméno, barva) VALUES("země", "modrá"), ("mars", "červená"), ("jupiter", "divný");

Popis připojení DSN (Název zdroje dat).

Nyní, když máme databázi, musíme nastavit DSN. DSN je zkratka pro název zdroje dat a je to soubor informací potřebných pro připojení k databázi, DSN je ve formě řetězce. Syntaxe se liší v závislosti na databázi, ke které se potřebujete připojit, ale protože používáme MySQL/MariaDB, musíme nastavit následující:

  • Typ ovladače použitého pro připojení;
  • Název hostitelského počítače, na kterém databáze běží;
  • Připojovací port (volitelný);
  • Jméno databáze;
  • Kódování (volitelné).

Formát řádku v našem případě bude tento (uložíme jej do proměnné $dsn):

$dsn = "mysql:host=localhost;port=3306;dbname=solar_system;charset=utf8";

Nejprve nastavíme prefix databáze nebo prefix databáze. V tomto případě, protože se připojujeme k databázi typu MySQL/MariaDB, používáme mysql. Předponu jsme pak oddělili od zbytku řádku dvojtečkou a každý následující oddíl byl od zbytku oddělen středníkem.

V dalších dvou částech jsme specifikovali název hostitele, na kterém databáze běží, a port použitý pro připojení. Pokud není zadán žádný port, použije se výchozí port, v tomto případě 3306. Bezprostředně za názvem databáze je znaková sada .

Vytvoření objektu PDO

Nyní, když je naše DSN připraveno, začneme vytvářet objekt PDO. Konstruktor PDO používá řetězec DSN jako první parametr, uživatelské jméno databáze jako druhý parametr, heslo jako třetí a pole volitelných nastavení jako čtvrtý.

$options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; $pdo = nové PDO($dsn, "testuser", "testpassword", $options);

Nastavení lze také nastavit po vytvoření objektu pomocí metody SetAttribute():

$pdo->SetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Konfigurace PDO pro zobrazení chyb

Podívejme se na některé možnosti dostupné pro PDO::ATTR_ERRMODE. Tyto možnosti jsou extrémně důležité, protože určují, jak se PDO chová, když dojde k chybě. Možné možnosti:

PDO::ERRMODE_SILENT

Výchozí možnost. PDO jednoduše vyvolá chybový kód a chybovou zprávu. Lze je získat pomocí metod errorCode() a errorInfo().

PDO::ERRMODE_EXCEPTION

Tuto možnost je dle mého názoru doporučeno využít. S jeho pomocí PDO kromě vydání chybového kódu a informace vyhodí PDOException, která přeruší provádění skriptu a hodí se i pro transakce PDO (podíváme se na ně trochu později).

PDO::ERRMODE_WARNING

S touto volbou PDO zobrazí chybový kód a zprávu stejně jako PDO::ERRMODE_SILENT , ale také zobrazí varování WARNING, které nepřeruší skript.

Nastavení výchozí metody vzorkování

Další důležité nastavení je regulováno pomocí konstanty PDO::DEFAULT_FETCH_MODE. Umožňuje vám nakonfigurovat výchozí operaci metody fetch(), která bude použita k získání výsledků požadavku. Zde jsou nejčastěji používané možnosti:

PDO::FETCH_BOTH

Při jeho použití budou získané výsledky indexovány jak celými čísly, tak názvy sloupců. Jeho použití v metodě k získání řádku z tabulky planet nám poskytne následující výsledky:

$stmt = $pdo->query("SELECT * FROM planet"); $results = $stmt->fetch(PDO::FETCH_BOTH); Pole ( => 1 => 1 => země => země => modrá => modrá)

PDO::FETCH_ASSOC

S touto konstantou budou výsledky zapsány do asociativního pole, ve kterém bude každý klíč názvem sloupce a každá hodnota bude představovat konkrétní hodnotu v řádku:

$stmt = $pdo->query("SELECT * FROM planet"); $results = $stmt->fetch(PDO::FETCH_ASSOC); Pole ( => 1 => země => modrá)

PDO::FETCH_NUM

Pomocí konstanty PDO::FETCH_NUM získáme pole indexované 0:

Pole ( => 1 => země => modrá)

PDO::FETCH_COLUMN

Tato konstanta je užitečná pro získání pouze hodnot ze sloupce a metoda vrátí všechny výsledky v jednoduchém jednorozměrném poli. Zde je například požadavek:

$stmt = $pdo->query("VYBRAT jméno FROM planet");

Jako výsledek:

Array ( => Země => Mars => Jupiter)

PDO::FETCH_KEY_PAIR

Tato konstanta je užitečná, když potřebujete získat hodnoty ze dvou sloupců. Metoda fetchAll() vrátí výsledky jako asociativní pole. V tomto poli budou data z prvního sloupce zadána ve formě klíčů a z druhého - jako hodnoty:

$stmt = $pdo->query("VYBRAT jméno, barvu FROM planet"); $result = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);

Jako výsledek:

Pole ( => modrá => červená => divná)

PDO::FETCH_OBJECT

Při použití konstanty PDO::FETCH_OBJECT bude pro každý načtený řádek vytvořen anonymní objekt. Jeho (veřejné) vlastnosti budou pojmenovány stejně jako sloupce a výsledky dotazu budou použity jako hodnoty. Použití této metody pro stejný dotaz jako výše poskytne následující výsledek:

$results = $stmt->fetch(PDO::FETCH_OBJ); objekt stdClass ( => země => modrá)

PDO::FETCH_CLASS

Stejně jako předchozí konstanta přiřadí hodnoty sloupců vlastnostem objektu, ale v tomto případě musíme nakonfigurovat existující třídu, která bude použita k vytvoření objektu. Pro demonstraci nejprve vytvoříme třídu:

Třída Planet ( private $name; private $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; ) )

Nevěnujte pozornost jednoduchosti kódu, podívejme se raději na třídu Planet, kterou jsme vytvořili: má ve svých vlastnostech privátní a třída nemá konstruktor. Nyní se pokusíme získat výsledky.

Když používáte fetch() s PDO::FETCH_CLASS, musíte před pokusem o načtení dat použít metodu setFetchMode() na objektu, například:

$stmt = $pdo->query("VYBRAT jméno, barvu FROM planet"); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planeta");

Konstantu PDO::FETCH_CLASS zadáme jako první argument metody setFetchMode() a název třídy použité k vytvoření objektu (v našem případě „Planet“) jako druhý argument. Nyní spustíme kód:

$planeta = $stmt->fetch();

Výsledkem by měl být objekt Planet:

Var_dump($planeta); Planeta Objekt ( => Země => modrá)

Všimněte si, jak byly hodnoty vrácené z dotazu přiřazeny k odpovídajícím charakteristikám objektu, i když jsou soukromé.

Přiřazení charakteristik po vytvoření objektu

Třída „Planet“ neměla žádný konkrétní konstruktor, takže nebyly žádné problémy s přiřazováním charakteristik; ale co když má třída konstruktor, ve kterém se nastavují a mění vlastnosti? Protože hodnoty jsou přiřazeny před spuštěním konstruktoru, budou přepsány.

PDO pomáhá poskytovat konstantu FETCH_PROPS_LATE: při použití budou hodnoty přiřazeny po vytvoření objektu. Příklad:

Třída Planet ( private $name; private $color; public function __construct($name = měsíc, $color = šedá) ( $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() (vrátit $this->color; ) )

Upravili jsme naši třídu Planet, abychom vytvořili konstruktor, který bude mít dva argumenty: název název a barvu . Tyto argumenty mají základní hodnoty moon a grey, což znamená, že pokud nejsou zadány žádné jiné hodnoty, budou nastaveny.

V tomto případě, pokud nepoužijeme FETCH_PROPS_LATE, pak bez ohledu na to, jaké hodnoty jsou získány z databáze, všechny charakteristiky zůstanou základní, protože během procesu vytváření objektu budou přepsány. Chcete-li to zkontrolovat, spusťte následující dotaz:

$stmt = $pdo->query("SELECT jméno, barvu FROM solar_system WHERE name = "země""); $stmt->setFetchMode(PDO::FETCH_CLASS, "Planeta"); $planeta = $stmt->fetch();

Nyní se podíváme na objekt Planet a zkontrolujeme, které hodnoty odpovídají jeho charakteristikám:

Var_dump($planeta); 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í předvedeme řešení problémů pomocí konstanty FETCH_PROPS_LATE (a stejného dotazu jako předchozí):

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planeta"); $planeta = $stmt->fetch(); var_dump($planeta); object(Planet)#4 (2) ( ["name":"Planet":private]=> string(5) "země" ["color":"Planet":private]=> string(4) "modrá" )

Nakonec bylo dosaženo požadovaného výsledku. Ale co když konstruktor třídy nemá žádné základní hodnoty a musí být specifikovány? To je již jednodušší: parametry konstruktoru můžeme nastavit ve formě pole, jako třetí argument za názvem třídy, pomocí metody setFetchMode(). Změňme například konstruktor:

Planeta třídy ( private $name; private $color; public function __construct($name, $color) ( $this->name = $name; $this->color = $color; ) [...] )

Argumenty konstruktoru jsou nyní povinné, takže spustíme:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, "Planeta", ["měsíc", "šedá"]);

V tomto případě parametry, které specifikujeme, slouží pouze jako základní hodnoty požadované pro bezchybnou činnost objektu: budou přepsány hodnotami z databáze.

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

Je samozřejmě možné získat více výsledků najednou ve formě objektů, buď pomocí metody fetch() nebo pomocí smyčky:

Zatímco ($planet = $stmt->fetch()) ( // Něco společného s výsledky )

Nebo získat všechny výsledky najednou. V tomto případě, jak již bylo zmíněno dříve, při použití metody fetchAll() budete muset zadat režim načítání ne před spuštěním metody, ale v okamžiku, kdy se spustí:

$stmt->fetchAll(PDO::FETCH_CLASS|PDO_FETCH_PROPS_LATE, "Planeta", ["měsíc", "šedá"]);

PDO::FETCH_INTO

Při použití této konstanty PDO nevytváří nový objekt, ale aktualizuje charakteristiky existujícího objektu, ale pouze pokud je veřejný nebo pokud je uvnitř objektu použita metoda __set().

Připraveno na přímé požadavky

PDO má dva způsoby práce s dotazy: pomocí přímých a spolehlivějších - připravených.

Přímé požadavky

Existují dvě hlavní metody pro použití přímých dotazů: query() a exec() . První vytvoří objekt PDOStatemnt, ke kterému lze přistupovat pomocí metod fetch() nebo fetchAll(): pokud je používáte v případech, kdy se tabulka nemění, jako je SELECT .

Druhá metoda místo toho vrací číslo řádku, který byl dotazem změněn: používáme ho v případech, které nahrazují řádky, jako je INSERT, DELETE nebo UPDATE. Přímé dotazy by se měly používat pouze v případech, kdy v dotazech nejsou žádné proměnné a není pochyb o bezpečnosti metody.

Připravené dotazy

PDO také podporuje dvoukrokové připravené dotazy: ty jsou užitečné, když mají dotazy proměnné, a jsou obecně bezpečnější, protože veškerou potřebnou práci za nás udělá metoda Prepare(). Pojďme se podívat, jak se proměnné používají. Představte si, že chceme vložit charakteristiky planety do tabulky Planety. Nejprve si připravíme žádost:

$stmt = $pdo->prepare("INSERT INTO planet(name, color) VALUES(?, ?)");

Jak bylo uvedeno dříve, používáme metodu Prepare(), která jako argument bere SQL dotaz s použitím dočasných hodnot pro proměnné. Dočasné hodnoty mohou být dvou typů: polohové a jmenovité.

Poziční

Použitím? poziční dočasné hodnoty, kód je stručnější, ale musíme zadat data, která mají být vložena ve stejném pořadí jako názvy sloupců v poli poskytnutém jako argument metody execute():

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

Personalizované

Použitím pojmenovaných zástupných symbolů nepotřebujeme konkrétní pořadí, ale ve výsledku získáme více kódu. Při spuštění metody execute() musíme dodat data ve formě asociativního pole, kde každý klíč je název použité dočasné hodnoty a přidružená hodnota je to, co se přenese do dotazu. Například předchozí požadavek by byl:

$stmt = $pdo->prepare("INSERT INTO planet(name, color) VALUES(:name, :color)"); $stmt->execute(["name" => $planet->name, "color" => $planet->color]);

Pro dotazy, které upravují nebo jednoduše získávají informace z databáze, lze obě použít metody Prepare() a execute(). V prvním případě používáme k získání informací výše uvedené metody načítání a ve druhém metodu rowCount().

metody bindValue() a bindParam().

Metody bindValue() a bindParam() lze také použít k poskytnutí hodnot, které budou vloženy do požadavku. První váže hodnotu dané proměnné na poziční nebo pojmenovanou dočasnou hodnotu použitou při přípravě požadavku. Vezmeme-li jako příklad předchozí případ, uděláme:

$stmt->bindValue("name", $planet->name, PDO::PARAM_STR);

Hodnotu $planet->name svážeme s dočasnou hodnotou:name . Všimněte si, že pomocí obou metod bindValue() a bindParam() můžeme také určit typ proměnné jako třetí argument pomocí vhodné konstanty PDO, v tomto případě PDO::PARAM_STR .

Použitím bindParam() místo toho můžeme svázat proměnnou s vhodnou dočasnou hodnotou použitou při přípravě dotazu. Všimněte si, že v tomto případě je proměnná vázána na odkaz a její hodnota se změní na dočasnou pouze tehdy, když se spustí metoda execute(). Syntaxe je stejná jako minule:

$stmt->bindParam("name", $planet->name, PDO::PARAM_STR)

Svázali jsme proměnnou, nikoli její hodnotu, $planet->name, na:jméno ! Jak bylo řečeno výše, k nahrazení dojde pouze při spuštění metody execute(), takže dočasná hodnota bude v daném okamžiku nahrazena hodnotou proměnné.

Transakce PDO

Transakce umožňují zachovat konzistenci při spouštění více dotazů. Všechny dotazy jsou prováděny v dávkách a jsou aplikovány na databázi pouze v případě, že jsou všechny úspěšné. Transakce nebudou fungovat se všemi databázemi a ne se všemi konstrukcemi SQL, protože některé z nich způsobují problémy.

Jako extrémní a podivný příklad si představte, že uživatel musel vybrat seznam planet a pokaždé, když provedl nový výběr, museli byste před vložením nové smazat z databáze tu předchozí. Co když k odstranění dojde, ale vložení ne? Získáme uživatele bez planet! V zásadě se transakce používají takto:

$pdo->beginTransaction(); zkuste ( $stmt1 = $pdo->exec("DELETE FROM planet"); $stmt2 = $pdo->prepare("INSERT INTO planet(name, color) VALUES (?, ?)"); foreach ($planets as $planet) ( $stmt2->execute([$planet->getName(), $planet->getColor()]); ) $pdo->commit(); ) catch (PDOException $e) ( $pdo-> vrátit zpět (); )

Za prvé, metoda beginTransaction() na objektu PDO zakáže autocommit požadavku, poté jsou požadavky spuštěny v požadovaném pořadí. V tomto okamžiku, pokud nedojde k výjimce PDOException, jsou požadavky automaticky předávány prostřednictvím metody commit(), jinak jsou transakce zrušeny pomocí metody rollBack() a autocommit je obnoveno.

Tímto způsobem, s více požadavky, bude vždy konzistence. To je docela zřejmé, ale transakce PDO může používat pouze PDO::ATTR_ERRMODE nastavené na PDO::ERRMODE_EXCEPTION .

Bootstrap framework: rychlé adaptivní rozložení

Videokurz krok za krokem o základech adaptivního rozvržení v rámci Bootstrap.

Naučte se sázet jednoduše, rychle a efektivně pomocí výkonného a praktického nástroje.

Layout na objednávku a dostat zaplaceno.

Bezplatný kurz „Stránky na WordPressu“

Chcete ovládat WordPress CMS?

Získejte lekce o designu a rozložení webových stránek na WordPress.

Naučte se pracovat s motivy a stříhat rozvržení.

Zdarma video kurz kreslení návrhu webu, rozložení a instalace na CMS WordPress!

*Najetím myší pozastavíte rolování.

Zpět dopředu

Základy práce s rozšířením PDO

Dnes probereme velmi zajímavé téma – základy práce s rozšířením. CHOP pro PHP.

PDO (PHP Data Objects)- to je zjednodušeně řečeno rozhraní, které umožňuje pracovat s různými databázemi bez zohlednění jejich specifik. S PDO můžeme snadno přepínat a spravovat různé databáze. Aby to bylo jasnější, podívejme se na příklad.

Jak jsme měli být dříve připojeni k databázi MySQL?

Mysql_connect($hostitel, $uživatel, $heslo); mysql_select_db($db);

Chcete-li se připojit k SQLite měli jsme to napsat takto:

Sqlite_open($db);

Pokud potřebujeme databázi PostgreSQL, pak to musíte napsat takto:

Pg_connect("host=$host, dbname=$db, user=$user, password=$password");

Není to moc pohodlné, že? Ukazuje se, že pokud budeme chtít změnit databázi, budeme muset předělat spoustu kódu. A tak, aby se to napravilo, objevilo se speciální rozšíření PHP - CHOP.

Podívejme se, jak se nyní můžeme připojit k databázi:

$db = nové PDO("mysql:host=$host;dbname=$db", $uživatel, $heslo);

$db = nové PDO("sqlite:$db);

PostgreSQL:

$db = nové PDO("pgsql:host=$host;dbname=$db", $uživatel, $heslo);

Jak vidíte, vše je při starém, kromě přípojného vedení. To je jediný rozdíl.


Nyní se podívejme, jak jsme dříve museli provádět dotazy:

$sql = "INSERT INTO(jméno, email) VALUES($jméno, $email)"; // MySQL mysql_query($sql); // SQLite sqlite_query($sql); // PostgreSQL pg_query($sql);

Nyní z toho můžeme abstrahovat:

// PDO $result = $db->exec($sql);

Všechno! Náš požadavek bude proveden bez ohledu na to, jakou databázi používáme a do proměnné výsledek zobrazí počet ovlivněných řádků.

Takto ale z databáze něco nevybereme. Pro vzorkování musíme použít not exec, A dotaz.

$sql = "VYBRAT jméno FROM uživatelů"; $vysledek = $db->dotaz($sql);

Teď pojďme Připomeňme si bezpečnost, protože je potřeba zkontrolovat všechna data. Jak jsme to dělali předtím?

$sql = "VYBRAT * Z uživatelů WHERE jméno = $jméno"; $name = $_POST["jméno"]; // MySQL $name = mysql_real_escape_string($name); // SQLite $name = sqlite_escape_string($name); // PostgreSQL $name = pg_escape_string($name);

Teď to dělat nemusíme. CHOP udělá vše za nás.

$name = $db->quote($name); $vysledek = $db->dotaz($sql);

Samotné PDO vše zkontroluje a zpracuje přenášená data. Super? :) Ještě cool přijde! Pokračujme.

Jak jsme předtím převedli výsledek do pole? Podívejme se na databázi jako příklad MySQL.

$vysledek = mysql_query($sql); // Takže $row = mysql_fetch_assoc($result); // Nebo takhle... $row = mysql_fetch_array($result, FETCH_ASSOC);

Stejně jako u asociativního můžeme také získat očíslované pole. Nyní se podívejme, jak se to dělá v CHOP:

$stmt = $db->query($sql); //Asociativní $výsledek = $stmt->FETCH(PDO::FETCH_ASSOC); // Číslovaný $výsledek = $stmt->FETCH(PDO::FETCH_NUM); // Oba typy polí současně $result = $stmt->FETCH(PDO::FETCH_BOTH); // Objekt $vysledek = $stmt->FETCH(PDO::FETCH_OBJ);

Použití je také velmi snadné:

// Asociativní echo $result["name"]; // Číslované echo $result; // Echo objektu $result->name;

Pro "líné" existuje tato věc:

$stmt = $db->query($sql); $vysledek = $stmt->FETCH(PDO::FETCH_LAZY);

Vrátí všechny 3 typy najednou. Tito. Tento FETCH_BOTH A FETCH_OBJ spolu. Jak jste možná uhodli, po tomto lze k datům přistupovat třemi způsoby:

Echo $vysledek->jmeno; echo $result["jméno"]; echo $výsledek;

nicméně Vynést vrací pouze jeden záznam, takže pokud chceme získat všechny záznamy, musíme použít FetchAll.

$stmt = $db->query("SELECT * FROM users"); $result = $stmt->FetchAll(PDO::FETCH_ASSOC); foreach($result as $user) ( echo $user["jméno"]."
"; }

S tím ale souvisí ještě jedna skvělá věc Vynést. S jeho pomocí můžeme naši třídu naplnit daty z databáze automaticky.

Class User ( public $login; public $id; public function showInfo() ( echo " ".$this->id.""." : ".$this->login."
"; ) ) $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $stmt = $db->query("SELECT * FROM `users`"); $ result = $stmt->fetchAll(PDO::FETCH_CLASS, "Uživatel"); foreach($result as $user) ( $user->showInfo(); )

Jak vidíte, vše je velmi jednoduché. Potřebujeme pouze určit konstantu FETCH_CLASS a oddělené čárkou v uvozovkách, název třídy, kam budou data vložena.

Poté procházíme objektem a zobrazujeme informace, které potřebujeme.
Pozornost! Názvy vlastností ve třídě se musí shodovat s názvy polí v databázi.

Mimo jiné můžeme vytvořit tzv připravené dotazy. Jaké jsou jejich výhody?

1. Požadavek můžeme připravit jednou a poté jej spustit tolikrát, kolikrát potřebujeme. A to jak se stejnými, tak dalšími parametry.

Když je dotaz připraven, DBMS jej analyzuje, zkompiluje a optimalizuje svůj plán provádění. V případě složitých dotazů bude doba provádění patrná, pokud jej spustíme s jinými parametry. V případě připravených dotazů se to dělá jednou, a proto se ztrácí méně času.

2. Připravené parametry dotazu není nutné uvozovat, ovladač to provede automaticky. Pokud aplikace používá pouze připravené dotazy, pak jsou injekce SQL téměř nemožné.

PDO umí emulovat připravené dotazy, pokud nejsou podporovány ovladačem. Nyní se podívejme, jak je používat?

$stmt = $db->prepare("INSERT INTO users (name, login) VALUES (:name, :login)"); $stmt->bindParam(":name", $name); $stmt->bindParam(":login", $login); // Vložte jeden řádek s těmito hodnotami $name = "vasya"; $login = "vasya123"; $stmt->execute(); // Nyní další řádek s jinými hodnotami ​​$name = "petya"; $login = "petya123"; $stmt->execute();

Metoda bindParam nám umožňuje nastavit parametry. Myslím, že zde je vše jasné. Nejprve tam, kam chceme data vložit, napište následující řádek " :Název". A pak označíme, odkud budou pocházet. V tomto případě budou převzaty z proměnných název A přihlásit se.

Nyní můžeme tento požadavek s různými parametry použít tolikrát, kolikrát chceme, a k jeho provedení musíme zavolat metodu vykonat. Tyto byly jmenoval možnosti. Existuje také nejmenován.

$stmt = $db->prepare("INSERT INTO users (name, login) VALUES (?, ?)"); // Místo prvního otazníku budou vložena data z proměnné name $stmt->bindParam(1, $name); // Místo druhého otazníku budou vložena data z proměnné login $stmt->bindParam(2, $login); // Vložte jeden řádek s těmito hodnotami $name = "vasya"; $login = "vasya123"; $stmt->execute(); // Nyní další řádek s jinými hodnotami ​​$name = "petya"; $login = "petya123"; $stmt->execute();

Další bod - Jak zachytíme chyby?

Na to existuje třída Výjimka PDO. Doporučuji sepsat všechny požadavky do bloku Zkus chytit.

Zkuste ( $db = nové PDO("myql:host=localhost;dbname=test", "root", ""); $stmt = $db->query("SELECT * FROM users"); $result = $stmt ->fetch(PDO::FETCH_ASSOC); echo $result["login"]; ) catch(PDOException $e) ( echo "Chyba: ".$e->getMessage()."
"; echo "Na řádku: ".$e->getLine(); )

Tady jsme udělali chybu a napsali myql namísto mysql. A třída Výjimka PDO nám o tom napíše.

Má několik metod, ale nejpoužívanější jsou getMessage() který nám vrátí text chyby a getLine(), která vrátí číslo řádku, kde došlo k chybě.

A konečně, pojďme si něco říct transakce. Nejprve dám kód.

Zkuste ( $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $db->beginTransaction(); $stmt = $db->exec("INSERT INTO `users `(`přihlášení`) VALUES("login1")"); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES("login2")"); $stmt = $db- >exec("INSERT INTO `users`(`login`) VALUES("login3")"); $db->commit(); ) catch(PDOException $e) ( $db->rollBack(); )

Zde zahájíme transakci pomocí metody beginTransaction(). Následuje nějaký kód dotazu. Poté zavoláme metodu spáchat() abychom potvrdili naše změny. Pokud se něco pokazí, tak v bloku chytit nazýváme metodu vrátit zpět (), který vrátí všechna naše data do předchozího stavu.

"Proč jsou tyto transakce vlastně potřeba?" - ptáš se. Chcete-li odpovědět na tuto otázku, zvažte příklad, který jsem uvedl výše. Tam vložíte hodnotu do pole "login". login1, login2, login3.

Představme si to po vložení přihlášení 1 A přihlášení2, došlo k nějaké chybě. Ukazuje se, že tato data jsou vložena a přihlášení3- Ne. V mnoha případech je to nepřijatelné a v budoucnu to naruší aplikaci.

Právě proto, aby se takovým situacím předešlo, jsou transakce potřeba. Pokud selže náš skript, pak metoda vrátit zpět () vrátí vše do původní podoby. Tito. přihlášení 1 A přihlášení2 také nebude vložen. Pojďme tuto chybu napodobit.

Zkuste ( $db = new PDO("mysql:host=localhost;dbname=test", "root", ""); $db->beginTransaction(); $stmt = $db->exec("INSERT INTO `users `(`login`) VALUES("login1")"); $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES("login2")"); exit("error") ; $stmt = $db->exec("INSERT INTO `users`(`login`) VALUES("login3")"); $db->commit(); ) catch(PDOException $e) ( $db-> vrátit zpět (); )

Po vložení přihlášení 1 A přihlášení2 opustíme skript pomocí funkce výstup(). Vyhodíme výjimku, skončíme v bloku chytit a poté vše vrátíme do původní podoby. Když se nyní podíváme do databáze, tak tam neuvidíme přihlášení 1 A přihlášení2.

V tuto chvíli skončíme. Je zřejmé, že zde jsme nepokryli vše, co nám PDO poskytuje, ale naučili jsme se základy práce s ním. Podrobnější informace o tomto rozšíření vždy najdete na oficiálních stránkách PHP.

Materiál speciálně pro web připravil Vladislav Andreev

P.S. Chcete se posunout dále v ovládání PHP a OOP? Věnujte pozornost prémiovým lekcím o různých aspektech tvorby webových stránek, včetně programování v PHP, a také bezplatnému kurzu vytváření vlastního CMS systému v PHP od nuly pomocí OOP:

Líbil se vám materiál a chcete mi poděkovat?
Stačí sdílet se svými přáteli a kolegy!