Download: Programowanie_peardb

Transkrypt

Download: Programowanie_peardb
PROGRAMOWANIE
Pear::DB
Moduł PEAR::DB
Próbowanie gruszek
Programowanie w językach wysokiego poziomu, jakich jak PHP,
daje gwarancję, że kod może być
wykorzystany przez wiele osób.
Dlaczego nie zastosować tej zasady do programowania baz danych? Czy można jakoś pomóc
użytkownikom platform, które nie
obsługują MySQL?
STEVEN GOODWIN
U
żywając wspólnego interfejsu programowania API można sprawić,
aby program mógł pracować z różnymi bazami danych bez potrzeby modyfikacji kodu źródłowego. W tym miesiącu
Steven Goodwin próbuje tego dokonać przy
pomocy modułu PEAR::DB (ang. pear
– gruszka).
Cudowny moduł
PEAR::DB jest modułem PHP umożliwiającym kontrolę nad bazą danych, bez potrzeby
określenia, której bazy konkretnie używamy.
Znaczy to, że ten sam kod może być użyty do
dostępu zarówno do MySQL, jak i Oracle.
Jak to działa? Kluczem do powodzenia jest
stworzenie warstwy abstrakcji – uniwersalnego systemu lub interfejsu programowego, tak
żeby szczegóły implementacji pozostały niewidoczne. Większość z nas posługuje się po-
Co to jest Pear?
PEAR to skrót od PHP Extension and Application Repository (wydaje się, że niektórzy
zamieniają tu Application na Add-on), jest
to biblioteka dla kodu PHP, podobnie jak
CPAN dla PERL. Oprócz modułów dla baz
danych (DB) istnieje też kod obsługujący
HTML, a także autoryzacje i szyfrowanie.
72
Maj 2004
jęciem abstrakcji, często nie zdając
sobie z tego sprawy. Nawet programiści C – zatwardziali przestępcy
w świecie programowania, przez abstrakcję ułatwiają sobie życie. Każda
funkcja, wyrażenie czy instrukcja, dzięki
językowi C oddziela programistę od
szczegółów sprzętowych procesora.
Jest to jednak abstrakcja niskiego
poziomu.
Programowanie baz danych
w języku SQL jest abstrakcją
wysokiego poziomu. Baza
typu MySQL, PostgreSQL lub Oracle może
pracować w dowolny
sposób, według dowolnego algorytmu
i używając dowolnych
plików. Dzięki wykorzystaniu języka SQL nie
musimy się martwić o szczegóły działania bazy, zamiast tego
możemy poświęcić czas na ważniejsze zadania, jak tworzenie wydajnych zapytań typu inner join i select.
Niestety, ten rodzaj abstrakcji nie przenosi się na sposób, w jaki programujemy bazę danych, ponieważ każda z nich ma jednak swóje własne API. W PHP możemy zainicjować dialog z bazą MySQL o nazwie
fredbloggs przez użycie:
$db = mysql_connect('localU
host', „myuser”, „mypass”);
mysql_select_db('fredbloggs');
PostgreSQL wymaga abyśmy napisali:
$db = pg_connect('host=localU
host dbname=fredbloggs user=U
myuser password=mypass');
Mimo że większość z tych parametrów jest
opcjonalna, przenoszenie kodu pomiędzy
bazami danych jest ciągle bolesne, każde
polecenie „connect”, „select” i obsługa błędów muszą zostać przepisane na nowo, aby
działały z inną bazą danych. Musimy zmie-
www.linux-magazine.pl
niać
nie tylko
nazwy
funkcji,
ale
także
strukturę
i format argumentów. Musimy
również dostosować kody błędów. Odpowiedzią na problem jest oddzielenie specyficznej funkcji database_connect od określonej
bazy i użycie wspólnych wywołań API. Należy to zrobić dla każdej funkcji przyporządkowanej do określonej bazy danych.
Oczywiście wymaga to mnóstwo pracy.
Całe szczęście, że ktoś to zrobił za nas!
W PHP mamy kilka interfejsów programowych (API) dla baz danych. W tym artykule
skupimy się na PEAR::DB, jednym z wielu
dobrych modułów PEAR dostępnych pod
adresem [1]. Znajduje się on w fazie aktywnego rozwoju prowadzonego przez kilku najważniejszych programistów projektu PHP.
Obecna wersja uznawana za stabilną to 1.6.0.
Dla tych, którzy chcą porównać PERA::DB
z konkurencją polecamy ADOdb [2], Metaba-
Pear::DB
se [3] oraz PHPlib [4].
Wykorzystanie MySQL było zbawieniem,
a jednocześnie przekleństwem dla programistów PHP. Pozytywną stroną jest to, że
MySQL jest zintegrowany z obecną instalacją PHP, co oznacza, że każdy bez większych problemów może wykonać dobrą stronę internetową opartą na bazie danych. Niestety z tego powodu wielu programistów nie
dostrzega, że istnieją również inne bazy danych posiadające równie dobre wsparcie,
jak to widać w Tabeli 2 (bazy danych obsługiwane przez PHP). Dodatkowe informacje
na temat obecnej sytuacji można znaleźć
w pliku docs/STATUS.
Mając na uwadze powyższe rozważania,
artykuł będzie podążał najprostszą drogą od
MySQL do PEAR::DB. Przyjrzymy się też
prostemu przykładowi bazy danych kanałów telewizyjnych na stronie wygenerowanej za pomocą PHP.
Misja specjalna
Korzystanie z PEAR::DB polega właściwie
na aktualizacji oprogramowania, dlatego
wcześniej musimy dysponować już istniejącą aplikacją. Aby spełnić tę role powrócimy
do tematu artykułu sprzed miesiąca i naszego maila do bramki wideo [5]. Zamiast zapisywać kanały TV jawnie w pliku wsadowym,
umiejscowimy odnoszące się wpisy (stacje,
kanały i nazwy) w niedużej bazie danych.
Na początek wprowadzimy zrzut kodu
SQL do bazy danych w standardowy sposób,
zezwalając na dostęp odpowiedniemu użytkownikowi (na przykład w w w-data). Do bazy dostajemy się używając MySQL, tak jak
na Listingu 2.
W tym raczej prostym fragmencie kodu
(dla przejrzystości usunięto kontrolę błędów) mamy nie mniej niż 5 oddzielnych odwołań do MySQL. Zamiast odwoływania się
do tabeli tv.channels, niektórzy pewnie woleliby, żeby określić aktualną bazę, używając
$dbhost
$dbuser
$dbpass
$dbname
=
=
=
=
PROGRAMOWANIE
nieczne, jeżeli nie mamy uprawnień root-a
na komputerze, np.
'localhost';
'www-data';
'';
'tv';
Ale to jeszcze nie wystarczy. Potrzebujemy
warstwy abstrakcji, takiej jak PEAR::DB.
Większość instalacji zawiera domyślnie bibliotekę PEAR::DB, zwykle w /usr/share/pear. Aby potwierdzić, czy instalacja zawiera pełny system wpisujemy,
<?php
require_once 'DB.php';
?>
Jeżeli nie, możemy użyć do instalacji PEAR
Packet Manager (używając polecenia pear
install DB) lub ręcznie, używając archiwum
tar. Dalsze szczegóły co do procesu instalacji PEAR można znaleźć w podręczniku on-line, znajdującym się pod adresem [6]. Alternatywnie można skopiować pliki do katalogu domowego (say ~/pear/) i zmienić
ścieżkę dostępu PHP include. Będzie to ko-
<?php
ini_set('include_path', U
'~/pear/lib'.PATH_SEPARATOR.iniU
_get('include_path'));
?>
Teraz mamy dostęp do nowych funkcji obsługi baz danych, zgodnych z konwencją
nazw PEAR. Jak zacząć pracę z PEAR?
Oczywistym miejscem są funkcje podstawowe, jak connect i close. W porównaniu do
poprzednich wersji MySQL i PostgreSQL,
PEAR::DB wymaga jedynie nieznacznej
zmiany.
Ponieważ inne bazy danych mogą wymagać mniej lub więcej parametrów, prosta
funkcja zamiany, która zmieni nazwy parametrów nie będzie działać. Zamiast tego musimy określić nazwę źródła danych data source name, czyli DSN. Zbierzemy tym samym wszystkie możliwe argumenty do pojedynczego sformatowanego łańcucha znaków.
Listing 1: Przykładowa baza danych TV
CREATE DATABASE IF NOT EXISTS tv;
USE tv;
drop table IF EXISTS channels;
CREATE TABLE channels (
station smallint(2) NOT NULL default '0',
channel smallint(2) default NULL,
name varchar(10) default NULL,
PRIMARY KEY (station)
) TYPE=MyISAM;
INSERT INTO channel VALUES (1,55,'TVP 1');
INSERT INTO channel VALUES (2,62,'TVP 2');
INSERT INTO channel VALUES (3,59,'TVN');
INSERT INTO channel VALUES (4,65,'Polsat');
INSERT INTO channel VALUES (5,37,'TVP4');
Listing 2: Dostęp przez MySQL
mysql_select_db('tv');
Działa to w ten sam sposób, jak polecenie
use z linii komend MySQL, z tym że dodaje
jeszcze jedno wywołanie MySQL.
Po zmianie serwera bazy danych każde
odwołanie do mysql musi zostać przepisane.
Przy większej ilości funkcji i obsłudze większej ilości baz danych ilość powtórzeń w kodzie wzrasta. Zazwyczaj jedynym powodem
zmian jest przenoszenie hosta bazy danych,
użytkownika i hasła do oddzielnego pliku,
np. dbase.inc.
function GetStationsList()
{
$db = mysql_connect("localhost", "www-data", "");
$query = "SELECT * FROM tv.channels";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
print "$row[0] - $row[2] ($row[1])<br>";
}
mysql_free_result($result);
mysql_close($db);
}
www.linux-magazine.pl
Maj 2004
73
PROGRAMOWANIE
Pear::DB
Format tego łańcucha wygląda następująco:
phptype(dbsyntax)://username:U
password@protocol+hostspec/U
databasename
DSN wygląda jak adres internetowy, określa, gdzie się połączyć i w jaki sposób określona baza danych ma być użyta oraz jakich
opcji użyć podczas łączenia. Pierwsza część
opisuje, jakiej bazy użyto i zawiera opis rodzaju bazy (określanego jako phptype, np.:
mysql) oraz wszystkie specyficzne dla określonej bazy wymagania, podane w dbsyntax.
Lista phptype jest pokazana w Tabeli 2.
Często podawany przykład łańcucha dbsyntax jest nazwą odpowiedniego sterownika
podczas używania bazy ODBC (access, db2,
mssql). Nie jest to trudne do ustalenia, ale
dotyczy bardziej użytkowników Windows,
nie musimy więc dalej się tym zajmować.
Druga część DSN zawiera wszystko, co jest
niezależne od bazy danych, jak nazwa hosta,
port, nazwa użytkownika i hasło. Tak jak
w zwykłej funkcji mysql_connect, nie wszystkie parametry są obowiązkowe, w razie potrzeby mogą zostać opuszczone. Na przykład:
mysql://www-data@localhost/tv
Naturalnie nasz finalny kod zapisze te parametry we wspólnym pliku dbase.inc, tak jak
to poprzednio pokazaliśmy. DSN nie musi
być wyspecyfikowany jako łańcuch znaków.
Może być także podany jako tablica, jak to
zostało wyszczególnione w ramce -- DSN jako tablica. To rozwiązanie jest nieco szybsze, bo do inicjalizacji nie ma potrzeby pobierania żadnego łańcucha.
DSN pozwala też określić opcje inicjujące
przy użyciu zbliżonej do adresu internetowego metody?option1=value1&option2=value2. Dostępnych jest kilka opcji, które opisują
zarówno praktyczne cechy dotyczące połączenia (użycie SSL), jak i te pomocne w programowaniu (kontrola wiadomości o błędach).
DSN jako tablica
$dsn = array(
'phptype' => „mysql”,
'hostspec' => „localhost”,
'database' => „tv”,
'username' => „www-data”,
'password' => „”
);
$db = DB::connect($dsn);
74
Maj 2004
Ponieważ opcje te mogą się różnić między
określonymi kwerendami, nie będziemy ich
włączać do DSN. Zamiast tego utworzymy tablicę, która je wyszczególnia i przekażemy je
osobno do funkcji DB::connect.
$dsn = „$dbbackend://$dbuserU
bhost/$dbname”;
$options = array(‘debug’ => 2);
$db =& DB::connect($dsn, U
$options);
Opcje te mogą być w każdej chwili zmienione przez użycie funkcji:
$db->setOption('debug', 0);
Połączenie powinno działać (obsługą błędów zajmiemy się później), będziemy odtąd
mieć do dyspozycji obiekt bazodanowy o nazwie $db, który używany jest we wszystkich
innych wywołaniach tej bazy np. do zamykania bazy po użytkowaniu.
$db->disconnect();
Następnie musimy przystąpić do przystosowania istniejących funkcji do użycia nowego obiektu i stowarzyszonych funkcji. Nie
jest to trudne, ponieważ mają one bardzo
zbliżone nazwy do ich oryginalnych wersji
w MySQL. Zatem, na przykład mysql_query
stanie się query, a mysql_fetch_array będzie
fetchRow. Nasza podstawowa funkcja jest
pokazana na Listingu 3.
Czarne pudełko
Ponieważ wszystkie zapytania do bazy przechodzą przez sterownik PEAR::DB, kod wewnątrz sterownika ma możliwość zmiany,
a także narobienia bałaganu z zapytaniem.
To konkretna cena za przenośność i uniwersalność. Poziom dopuszczalnej ingerencji
można ustawiać w opcjach dotyczących
przenośności, dostępnych w metodzie setOption, którą już widzieliśmy.
Te kompromisy pomiędzy przenośnością
i wydajnością w wielkim stopniu zależą od
konkretnej aplikacji. Opcje te mogą być też
użyte do obsługi starszego kodu przez PEAR::DB. Według konwencji większość nazw
tablic jest opisana małymi literami. Na
przykład, jeżeli aplikacja próbuje pobrać
dane używając mieszanych, małych i dużych liter, nazwy zostaną automatycznie
przekonwertowane na małe litery:
$db->setOption('portability', U
DB_PORTABILITY_LOWERCASE);
Usuwa to element niespodzianki, który pojawia się, gdy nieznany kod zawiesza aplikację. Inne opcje dostępne tutaj są podane
w Tabeli 1.
Domyślnie wszystkie te opcje są włączone
dla zwiększenia wydajności, jednak od nas
zależy, które z nich będą włączone. Istnieją
też definicje dla DB_PORTABILITY_ALL
i DB_PORTABILITY_NONE, które przełączają flagi.
Przemieszczanie się
w tłumie
Nie wszystkie funkcje idą w kierunku uczynienia łatwiejszym dostępu do bazy danych.
Na przykład fetchRow ułatwia pobieranie
danych w formacie przyjaznym raczej dla
programisty. PEAR::DB obecnie wspiera
trzy takie formaty. Domyślnie będzie to tablica sortowana od zera, jak pokazano
w przykładzie powyżej. Opcjonalny para-
Listing 3: Konwencja nazw w PEAR
function PearVersion()
{
global $dbname, $dbhost, $dbuser, $dbbackend;
$dsn = „$dbbackend://$dbuser@$dbhost/$dbname”;
$db =& DB::connect($dsn);
$query = 'SELECT * FROM channels';
$result = $db->query($query);
while ($row = $result->fetchRow()) {
print „$row[0] – $row[2] ($row[1])<br>”;
}
$result->free();
$db->disconnect();
}
www.linux-magazine.pl
Pear::DB
Tabela 1:Opcje zawiązane z przenośnością
PROGRAMOWANIE
Opcja
Opis
Tabela 2: Obsługiwane
bazy danych
DB_PORTABILITY_LOWERCASE
Konwertuje nazwy pól i tabel na małe litery (przy get i fetch)
Name
Keyword
DB_PORTABILITY_RTRIM
Obcina wyjście od prawej
dBase
dbase
DB_PORTABILITY_DELETE_COUNT
Zawsze raportuje liczbę skasowanych rzędów
FrontBase
fbsql
DB_PORTABILITY_NUMROWS
Wspomaga numRows w Oracle
InterBase
ibase
DB_PORTABILITY_ERRORS
Odwzorowuje wiadomości o błędach między różnymi bazami danych
Informix
ifx
DB_PORTABILITY_NULL_TO_EMPTY
Konwertuje zera do pustych łańcuchów (przy get i fetch), ponieważ Oracle
nie rozpoznaje między nimi różnicy
Mini SQL
msql
Microsoft SQL Server
mssql
metr w DB_FETCHMODE_ORDERED
został w tym przykładzie pominięty. Jest to
użyteczne do obsługi prostych baz danych
lub wyświetlania tabel bez potrzeby znajomości nazw pól lub odniesień.
W większości jednak sytuacji numeryczne indeksy nie są wystarczająco opisowe,
możemy więc zażądać, aby rezultaty otrzymywać w skojarzonej tablicy. Kosztem
uogólnień otrzymamy dużo łatwiejszy do
analizy kod.
while ($row = $result->fetchRowU
(DB_FETCHMODE_ASSOC)) {
print $row['station'].' – U
'.$row['name'].' ('.$rowU
['channel'].')<br>';
}
W końcu fetchRow dostarcza sposobów na
użycie zorientowanych obiektowo możliwości PHP do zwracania obiektu dla każdego
wiersza tabeli wyników. Każda kolumna jest
oznaczona jako własność obiektu. Tak jak
poprzednio, sprawia to, że kod jest łatwiejszy do analizy, jednak możliwości zastosowania dla bardziej uniwersalnych aplikacji
są ograniczone.
while ($row = $result->fetchRowU
(DB_FETCHMODE_OBJECT)) {
print $row->station.' – U
'.$row->name. ' ('.$row->U
channel.')<br>';
}
Wykryć błąd
Żaden program nie jest właściwie napisany,
jeśli nie posiada obsługi błędów i dokumentacji. Rzeczy te nie fascynują programistów, ale są konieczne. Możliwości obsługi błędów w PEAR::DB zostały ujednolicone (choćby przez odpowiednie kody błędów) i wynikają z podstawowych możliwości obsługi błędów w PEAR_Error. W przypadku niepowodzenia jakiejś funkcji z PEAR::DB, większość z nich zwróci konkretną
klasę błędu – od najwyższej connect do najniższej getRow. Klasa ta nie tylko przechowuje błąd z funkcji PEAR, ale też dodatkowe informacje przydatne w usuwaniu problemów.
$db =& DB::connect($dsn);
// DB::isError is the same as U
PEAR::isError
if (DB::isError($db))
{
print $db->getMessage();
print $db->getDebugInfo();
}
Błędy mogą być także wychwytywane przy
użyciu standardowej procedury obsługi błędów w PEAR. Jest to definiowana przez
użytkownika funkcja, która będzie wywołana zawsze, gdy moduł PEAR (jak db) wygeneruje błąd. Ta funkcja może być użyta do
stworzenia kodu generującego dla użytkownika standardową stronę HTML, informującą administratora o problemie.
Programy obsługi błędów są tradycyjnie
połączone z możliwościami PHP, co do
przekazywania wyników do buforowanego
wyjścia, co umożliwia czyszczenie wynikowego kodu HTML. Jednak tradycyjne błędy
(takie jak dzielenie przez zero) nie będą tu
wyłapywane.
// Przygotuj uchwyt
PEAR::setErrorHandling(PEAR_ERRU
OR_CALLBACK, 'error_function');
// włącz buforowanie wyników
ob_start();
// uruchom kod
PearVersion();
MySQL
mysql
MySQL >=4.1
mysql4
Oracle 7/8/9
oci8
ODBC
odbc
PostgreSQL
pgsql
SQLite
sqlite
Sybase
sybase
// zrzuć zawartość bufora
ob_end_flush();
// przygotuj uchwyt
function error_function($err)
{
ob_end_clean();
print 'Wystapil blad ('.$err->U
getMessage().')!');
exit;
}
Właściwości PEAR::DB
PEAR::DB jest rzeczywiście tak łatwy, jak
na to wygląda. Złożoność pochodzi od samego SQL. PEAR::DB chroni jedynie przed
niektórymi problemami. SQL istnieje od
wielu lat, jednak w ramach wojen pomiędzy
poszczególnymi dostawcami zostały dodane
różne rozszerzenia SQL, co sprawia, że poszczególne implementacje są ze sobą niekompatybilne.
Mimo że komitet ANSI kierował standaryzacją części języka (podstawowe wersje
select, insert i update są w pełni przenośne),
istnieje nadal wiele problemów. Pisanie
w standardowym SQL-u jest wyzwaniem samym w sobie i istnieje kilka reguł, które należy w tym celu poznać. Większość specjalizujących się w bazach danych programistów
zna je doskonale, początkujący mogą sięgnąć do tutoriali, takich jak [7].
Często chcemy wiedzieć, jak baza zare-
Listing 4: tableInfo
$tableinfo = $result->tableInfo());
for($col=0; $col < $result->numCols(); $col++) {
print $tableinfo[$col]['name']." is a ".$tableinfo[$col]['type'];
}
www.linux-magazine.pl
Maj 2004
75
PROGRAMOWANIE
Pear::DB
Tabela 3:
Zakres testowania
przy pomocy provides
Tabela 4:
Ograniczenia SQL
Database
SQL Syntax
string
Functionality
DB2
prepare
Czy baza sprawdza wstępnie
kolejkę SQL
select * from table fetch
first 10 rows only
Informix
select first 10 * from table
pconnect
Persistentne połączenia
Microsoft SQL Server
select top 10 * from table
transactions
Czy baza wspiera transakcje
MySQL
select * from table limit 10
limit
Ograniczone kolejki select
Oracle 8i
select * from (select * from
table) where rownum <= 10
PostgreSQL
select * from table limit 10
aguje na określone zapytanie, zanim je wykonamy. Wymaga to dodatkowej pracy, którą albo wykonamy sami albo poprzez PEAR::DB. Niestety, jeżeli już dostaliśmy się
do bazy, nie ma często sposobu, aby dowiedzieć się, czy potrafi ona obsługiwać określone polecenia SQL.
Metoda provides pokazuje możliwości aktualnej bazy danych. Pozwala na przełączanie pomiędzy dwoma ręcznie dostrojonymi
kwerendami, tak aby zwiększyć wydajność.
Przecież nowa wersja bazy danych może
oferować nową cechę, dlatego metoda provides użyta w PEAR::DB umożliwia budowanie bardziej optymalnych kwerend dla naszej bazy bez znajomości szczegółów o nowej bazie danych.
if ($db->providesU
('transactions'))
print 'Super! Ta funkcja jest U
obsługiwana';
Zakres możliwości, które można przetestować, pokazano w Tabeli 3.
W każdym z przypadków możliwe jest, że
baza nie wspiera sama w sobie danej funkcji. Słowem kluczowym jest tutaj natively,
ponieważ istnieje rozróżnienie pomiędzy
wewnętrznym procesorem bazy a sterownikiem PEAR::DB. Na przykład, jeżeli baza
danych nie posiada wsparcia dla poleceń
prepare/execute, sterownik obsłuży pojawienie się tego polecenia poprzez emulację.
Kuszące może być tu użycie provides do
utworzenia zupełnie odmiennych, ręcznie
optymalizowanych kolejek dla każdej bazy
danych. W większości przypadków nie jest
to konieczne. Powód (niektórzy powiedzą
wymówka) dla tego rodzaju zwyczajów wynika z rozszerzeń, które są widoczne wewnątrz SQL. Typowy przykład tego problemu pochodzi z ograniczeń kolejek select, co
prowadziło do zatrzymania generowania rezultatów po, powiedzmy, pierwszych dziesięciu rzędach. Obecnie wszystkie bazy danych potrafią wykonać to działanie, lecz za
76
Maj 2004
Z uwagi na błędy, czasem konieczna jest
wiedza o tym, jakiej dokładnie używamy bazy. Jeżeli nie można usunąć błędów, musimy
wiedzieć, gdzie się one znajdują, aby przynajmniej móc ich unikać.
print $db->phptype;
Polecenie powyżej pokaże nam te same identyfikatory, jak te w Tabeli 2. Szczegóły dotyczące błędów w bazach danych nie są celem
niniejszego artykułu.
pomocą różnych kolejek (Tabela 4). Pisanie
Tylko dla was
kodu dla każdego z przykładów to mnóstwo
PEAR::DB nie tylko umożliwia budowanie
dodatkowej pracy.
warstwy abstrakcji dla kodu obsługi baz daPonieważ nie możemy się troszczyć
nych. Jako bonus otrzymujemy kilka narzęo każdą bazę danych (razem z nowymi i tydzi do obsługi samych danych, jak numRows
mi jeszcze nie napisanymi), nasz kod stai numCols.
nie się bardzo szybko nieprzenośny i narażony na
Listing 5: assertExtension
obumieranie.
Problem
ten łatwo rozwiązać, jakif (DB::assertExtension('oci8'))
kolwiek musimy tu zastoprint 'Uzywamy Oracle jesli musimy...';
sować te same zasady absif (DB::assertExtension('mysql”))
trakcyjności. PEAR::DB
print „Uzywam MySQL bo lepiej go znam...”;
dostarcza metody nazywającej się limitQuery,
która ukrywa przed nami dokładną składprint „Polecenie select zwrocilo U
nię i stosuje to, co jest kompatybilne z ak'.$result->numRows(). ' rows';
tualną bazą danych. Jest to bardziej optyprint 'Polecenie select zwrocilo U
malne niż pisanie oddzielnych kolejek dla
'.$result->numCols(). ' cols';
każdej bazy.
Efekty działania tych funkcji są samowyjaśniające i można to wydedukować z samego
$query = „SELECT name FROM U
zapytania select. Oszczędzają ręcznego liczechannels”; // no reference to U
nia kolumn, gdy kwerenda jest generowana
limits here!
automatycznie.
$result = limitQueryU
Mamy też metodę tableInfo, która dostar($query, 2, 1);
cza informacji, takich jak nazwa i typ dla
każdej kolumny w rezultatach zapytania.
Polecenie to pobiera 1 wiersz z rezultatów
Jest to użyteczne nie tylko przy wynajdywawykonanej kwerendy, zaczynając od indeksu
niu błędów, ale także do tworzenia uniwer2, ponieważ trzeci wpis liczy się od 0.
salnych aplikacji bazodanowych. Mamy
Jeżeli zapytanie typu select może zostać
możliwość zaznaczania kolorem różnych kozmodyfikowane, tak aby utworzyć odpolumn w zależności od ich rodzaju lub podwiedni łańcuch w pytaniu do bazy danych,
świetlania pola klucza (Listing 4).
$db->provides('limit') zwróci alter i kwePoza name i type można (używając składni
renda, zanim będzie przekazana dalej, zoużytej w przykładzie powyżej) wykonywać
stanie przekształcona przez sterownik PEpytania o len (długość), flags (wskazuje na
AR::DB. W przeciwnym razie provides
primary key) i table – nazwę tabeli, dla każzwróciłoby emulate, ponieważ sterownik
dej kolumny.
może wykonywać kwerendę na zasadzie
Mimo że większość interfejsów programowiersz za wierszem, albo mogłaby zostać
wych API wspiera zapytanie typu select, możezwrócona wartość false. Powinno się zawsze
my też zostać obdarowani rezultatami kwekolejkować zasoby bazy używając rezultatu
rend typu insert. Jednym z przydatnych narzęz provides, a nie polegać na własnej pamiędzi jest metoda affectedRows, zwracająca liczci czy doświadczeniu. Tabela 5 pokazuje
bę wierszy, na które ma wpływ kwerenda typu
aktualny zestaw sterowników.
www.linux-magazine.pl
Pear::DB
cia wewnątrz aplikacji (Listing 5).
Database
prepare
pconnect
transactions
limit
Pomimo swojej
FrontBase
false
true
true
emulate
nazwy, nie jest to
InterBase
true
true
true
false
asercja w tradycyjInformix
false
true
true
emulate
nym
programiMini SQL
false
true
false
emulate
stycznym sensie,
Microsoft SQL
false
true
true
emulate
ponieważ żaden
MySQL
false
true
true
alter
błąd nie jest tu wyOracle 8i
false
true
true
alter
raźnie zwracany.
ODBC
true
true
false
emulate
Metoda stwierdza
PostgreSQL
false
true
true
alter
jedynie, czy jakieś
Sybase
false
true
false
emulate
rozszerzenie istnieje lub nie.
Wspomnijmy też o łączeniu pary prepare
insert, delete czy update. Mamy też możliwość
i execute. Jest to właściwość pozwalająca
generowania unikalnych ID, używając do tego
przygotować prepare kwerende do wielofunkcji sekwencyjnej nextID, która jest pokrotnego użycia poprzez to, że elementy te
mocna przy generowaniu unikalnych kluczy –
są prekompilowane i rozkładane na tokeny.
nie jest to obsługiwane przez MySQL. Na
Kwerenda będzie się składać z miejsc zareprzykład:
zerwowanych dla innych informacji, dlatego może być wykonywana execute wiele ra// Get a new ID.
zy z różnymi danymi wstawianymi w miej$id = $db->nextID('sequence'); U
sca zarezerwowane (Listing 6).
// (the sequence will be U
MetodaexecuteMultiple sprawdza zapytacreated if it doesn't exist)
nia SQL,
Inną użyteczną właściwością jest statycznie
deklarowana metoda assertExtension – nie
INSERT INTO channels (station, U
wymaga obiektu bazy danych i będzie wskaname, channel) VALUES (6, U
zywała, które z funkcji zostały zawarte
'Video', 0);
w obecnej instalacji. Można określić, które
INSERT INTO channels (station, U
bazy danych są zainstalowane w systemie i
name, channel) VALUES (7, U
które z nich najbardziej pasują nam do uży'PS2', 39);
Tabela 5: Co umożliwia provides
PROGRAMOWANIE
Metoda executeMultiple zatrzyma się na
pierwszym błędzie, aby temu zapobiec będziemy musieli wykonywać każde kolejne
zapytanie z pomocą metody execute. Na
przykład,
foreach ($data as $row) {
$db->execute($generic, $row);
}
Ponadto tablica danych musi być indeksowana od zera. W większości przypadków powinniśmy zauważyć zwiększenie szybkości, gdy
jednocześnie wprowadzanych będzie do bazy
kilka wpisów. Korzyść jednak zależy od tego,
czy baza danych posiada bezpośrednie
wsparcie dla tej funkcji, niestety nie wszystkie posiadają.
Idziemy na wojnę
Posiadając w swoim arsenale PEAR::DB
otrzymujemy możliwość atakowania większości baz danych, bez martwienia się
o brakujące funkcje. Dzięki szerokiemu zakresowi metod możemy napisać w PHP dobrą, niezależną od platformy aplikację bazodanową, bez przejmowania się pomniejszymi problemami.
■
INFO
[1] PEAR: http://www.pear.php.net
[2] ADOdb: http://php.weblogs.com/adodb
Listing 6: Przygotowanie zapytania
$generic = $db->prepare('INSERT INTO channels (station, name, channel)
VALUES (?,?,?)');
$data = array (
array(6, 'Video', 0),
array(7, 'PS2', 39)
);
$res = $db->executeMultiple($generic, $data);
[3] Metabase:
http://freshmeat.net/projects/metabase/
[4] PHPlib: http://phplib.sourceforge.net/
[5] Linux Magazine, nr 41,
kwiecień 2004, str. 72
[6] PEAR manual: http://www.pear.php.net/
manual/en/installation.cli.php
[7] Writing Portable SQL Code:
http://php.weblogs.com/portable_sql
Prenumerata Linux Magazine
Nie przegap takiej okazji
■ Zamawiając prenumeratę oszczędzasz!
■ Płacisz jak za 9 numerów, a otrzymujesz 12!
■ Z każdym numerem DVD lub płyta CD-ROM.
Najszybszy sposób zamówienia prenumeraty:
http://www.linux-magazine.pl
Infolinia: 0801-800-105

Podobne dokumenty