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