[php][sql] wiele interfejsów dla bazy danych

0

Potzrebuje sobie napisac program w którym można by w konfiguracji wybrać z jakiej bazy danych program ma korzystać.

np select i w nim MySQL i SQLlite. A w programie będzie w zwiazku z tym zapytanie:

if($x)
     mysql_query($query);
else
     sqlite_query($db, $query);

Tylko nie mam pomysłu jak sie za to zabrać [???] Pisał ktoś juz coś podobnego?

0

Zobacz modul obslugujacy bazy danych w np.: phpnuke - www.phpnuke.org albo forum phpbb.
Korzystają z kilkunastu baz.

0

proste. tworzymy klasę obsługi baz danych z jakimiś funkcjami o jednakowych nazwach w każdej klasie.

i potem mamy np. klasę DBmySQL i DBSQLite

i w programie robimy coś takiego:

if ($konfiguracja == 'mySQL') {
  $db = new DBmySQL;
} else {
  $db = new DBSQLite;
}

$db->Query("SELECT * FROM something");
0

proste. tworzymy klasę obsługi baz danych z jakimiś funkcjami o jednakowych nazwach w każdej klasie.

Good idea.. tyle, że ja nie umiem programować obiektowo :/ Widze, że w dzisiejszych czasach bez tego nie mozna się obejść dlatego się przemoge... tak samo jak kiedyś sie przemogłem i nauczyłem sql'a :)
Biore się za pisanie, jak czegos nie bede umiał rozgryźć to jeszcze spytam :P

pozdro

0

Obadaj źródła Coyote:
db.php
mysql.php

0

Już sobie poradziłem bez cudzych źródeł, spłodziłem takie cuś:

class db_sqlite
{
    // dane które będą zwracać funkcje
    var $db = '';
    var $res = '';
    var $row = '';
    var $count = 0;
    // dane potrzebne do połączenia się z bazą
    var $dbname = '';
    var $usrname = '';
    var $usrpass = '';

    // konstruktor klasy
    function db_sqlite()
    {
         if(!extension_loaded('sqlite'))
         {
              echo('SQLite extension no exists! See <a href="http://sqlite.org">sqlite.org</a>.');
	      die();
         }
    }
    
    // funkcja zapisuje bład, wyświetla go i zamyka program
    function sql_error($msg)
    {
         $n = ERR_LOG;
         $s = @filesize($n);
         if (!@file_exists($n) | $s >= ERR_LOG_SIZE)
         {
             @chmod($n, 0606);
             $file = @fopen($n, 'w+');
         }
         else
             $file = @fopen($n, 'a+');

	 $msg = "Error: in " . __FILE__ . " on line <span style=\"font-weight: bold;\">" . __LINE__ . "</span>. " . $msg;

         @flock($file, 2);
         @fwrite($file, strip_tags($msg) . "\n"); // zapisanie linii
         @flock($file, 3); // odblokowanie pliku
         @fclose($file);
         echo($msg);
         die();
    }
    
    // łaczy się z bazą dancyh
    function connect()
    {
	if(!file_exists($this -> dbname))
	{
	      $this -> sql_error("Database <span style=\"font-weight: bold;\">" . $this -> dbname . "</span> doesn't exists!");
	}
        $this -> db = sqlite_open($this -> dbname);

    }

    // wykonuej zapytanie
    function sql_query($query)
    {
        $this -> res = @sqlite_query($this -> db, $query);

	$error = sqlite_last_error($this -> db);
        if($error) {
	    $this -> sql_error("SQLite error number <span style=\"font-weight: bold;\">$error</span> (" . sqlite_error_string($error) . ")");
        }
        
        return $this -> res;
    }
    
    // zwraca tablice z podanego zasobu
    function fetch_array($res)
    {
        if(!$res) {
	    $this -> sql_error("<span style=\"font-weight: bold;\">sqlite_fetch_array</span> expect resource, null given.");
        }
	$this -> row = sqlite_fetch_array($res, SQLITE_ASSOC);
	return $this -> row;
    }
    
    // zwraca liczbe wierszy w danycm zasobie
    function num_rows($res)
    {
        if(!$res) {
	    $this -> sql_error("<span style=\"font-weight: bold;\">sqlite_num_rows</span> expect resource, null given.");
        }
	$this -> count = sqlite_num_rows($res);
	return $this -> count;
    }

    // zamyka baze dacnych
    function close()
    {
	sqlite_close($this -> db);
    }
}

Wklejam to dla potomnych... a moze ktos znajdzie jakiś błąd :|

0

Użyłeś tylko jednej klasy, która stanowi opakowanie dla strukturalnego kodu.

Chcemy dysponować pewną metodą, w tym wypadku query(text), która będzie korzystać z różnych implementacji: raz będzie posługiwać się mysql_query(text) a innym razem sqlite_query(text). Z jakiego mechanizmu programowania obiektowego skorzystamy ?

Z polimorfizmu. Aby szczegóły nie zasłoniły istoty rozwiązania, rozpiszmy to bardzo ogólnie:

abstract class Database {
var dbConnection;
abstract function query(queryString);
}

class MySQL extends Database {
function MySQL(connectionString) {...}
function query(queryString) {...}
}

class SQLite extends Database {
function SQLite(connectionString) {...}
function query(queryString) {...}
}

Klasy i metody abstrakcyjne są udostępnione w PHP 5.x. Jeśli natomist jesteśmy skazani na PHP 4.x można osiągnąć ten cel następująco:

class Database {
var dbConnection;
function query(queryString) { die(); }
}

teraz do dzieła ! Wystarczy tylko wlać implementację w tą foremkę a potem używać jej następująco (zakładam, że istnieje tablica konfiguracyjna $conf):

if($conf['db']=="mysql")
$db=new MySQL("... dane wymagane do połączenia");
else
$db=new SQLite("... dane wymagane do połączenia");

// od tego miejsca zupełnie nie obchodzi nas z jaką konkretnie bazą pracujemy
$db->query("Select * from ....");

0

Kapustka twojego rozwiązania w zasadzie nie rozumiem, a przecież gdy stworze drugą prawie identyczną klase w której będą zapytania mysl_query a nie sqllite_query to zasadniczo efekt:

if($conf['db']=="mysql")
$db=new MySQL("... dane wymagane do połączenia");
else
$db=new SQLite("... dane wymagane do połączenia");

// od tego miejsca zupełnie nie obchodzi nas z jaką konkretnie bazą pracujemy
$db->query("Select * from ....");

będzie taki sam. Więc po co jest polimorfizm [???]

0

Kooba - chodzi o to, żeby najpierw napisać klasę czysto obstrakcyjną jako szablon i na jej podstawie pisać klasy potomne. Dzięki temu widząc kod klasy abstrakcyjnej widzisz jakie metody muszą być napisane w klasie potomnej, a nie musisz zaglądać do klasy MySQL i wśród setek linii kodu szukać nazw wszystkich metod.

Kapustka - początkowo nie wiedziałem o co Ci chodzi, ale szacunek - znowu się czegoś nauczyłem o OOP (dopiero zaczynam). [browar]

0

Tak naprawdę nie mamy tu polimorfizmu - PHP nie ma mocnej kontroli typów a jest ona wymagana w tym mechanizmie.

W gruncie rzeczy, jeśli byśmy do klas MySQL i SQLite dopisali atrybut dbConnection (który, jako wspólny, został umieszczony w nadklasie) to program zadziała bez obecności abstrakcyjnej klasy Database.

Jakie korzyści daje użycie abstrakcyjnej klasy Database ?

  • czytelne wyspecyfikowanie wspólnego interfejsu
  • zawarcie wspólnych pól (dbConnection)

A dlaczego używamy dwóch klas: MySQL i SQLite zamiast jednej (jak zaproponowałeś początkowo).

  • bardzo łatwo można dodać w przyszłości obsługę kolejnych baz danych bez konieczności modyfikowania już działającego kodu.

Obsługi nowej bazy polega na dopisaniu kolejnej klasy realizującej interfejs Database. Nie dotykamy nawet jednego wiersza już działającego i przetestowanego kodu klass MySQL i SQLite.

dzięki silent, pozdrawiam

0

Kapustka, ja obiektowo pisze od wczoraj (:d) i dalej nie widze sensu w tym co mówisz... czy mógłbyć pokazac mi to na konkretach: to znaczy przykładowo zbudować gotową kalse która by tylko wykonywała zapytanie w SQLlite i w MySQL... myśle że jak zobacze to wszystko w praktyce to przyznam Ci racje że twoje rozwiązanie jest lepsze :)

0

Pytanie do Kapustki - na jakim poziomie robić kontrolę błędów? Czy w klasie MySQL w każdej metodzie ma być sprawdzanie błędów czy klasa korzystająca z obiektu klasy MySQL ma sprawdzać co zwraca każda metoda?

Napisałem na szybko coś takiego - napisz co o tym sądzisz:

<?

class cDatabase
{
	
	var $rConnection;
	var $rResult;
	
	function Connect()
	{
		// return true or false on connection
	}

	function Close()
	{
		// return true or false on close connection
	}
	
	function Query()
	{
		// return true or false on query
	}
	
	function FetchAssoc()
	{
		// return table row as associative array or false
	}
	
	function Error()
	{
		// return true if error occurs
	}
	
	function ErrorString()
	{
		// return database error string
	}
}

class cMySQL extends cDatabase
{
	function Connect( $sDbHost, $sDbUser, $sDbPass )
	{
		$this->rConnection = @mysql_connect( $sDbHost, $sDbUser, $sDbPass );
		if ( $this->rConnection )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	function Close()
	{
		if ( @mysql_close($this->rConnection) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	function Query( $sQuery )
	{
		$this->rResult = @mysql_query( $sQuery );
		if ( $this->rResult )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	function FetchAssoc()
	{
		if ( $row = @mysql_fetch_assoc( $this->rResult ) )
		{
			return $row;
		}
		else
		{
			return false;
		}
	}
	
	function Error()
	{
		if ( mysql_errno( $this->rConnection ) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	function ErrorString()
	{
		return mysql_error();
	}
}

?>

teraz korzystanie ma być takie:

$db=new cMySQL;
if ( $db->Connect( 'host', 'user', 'pass' ) )
{
	// jakieś działanie
}
else
{
	//inne działanie
}

??
Czy jakoś inaczej??

0

Z błędami jest taka generalna zasada: powinny być wyłapywane i obsługiwane w takiej klasie, która ma odpowiednią wiedzę i możliwości działania.

Czy klasa cMySQL ma odpowiednią wiedzę aby zadziałać w sytuacji gdy nie może wykonać zapytania ? Inaczej mówiąc: Co będzie mogła zrobić w takiej sytuacji ?

Będzie mogła powtórzyć próbę kilka razy, ewentualnie odnowić połączenie i spróbować jeszcze raz. Ostatecznie może wyświetlić komunikat. Prawdopodobnie takie działanie jest wystarczające.

Ale wyobraźmy sobie, że utrzymujemy i cały czas synchronizujemy zaposową bazę danych (co jest bardzo kosztowne ale bezpieczeństwo podnosi się drastycznie). W sytuacji problemu z podstawową bazą korzystamy z zapasowej. Czy cMySQL ma dostateczną wiedzę aby dokonać takiej podmiany ? Nie. Taka obsługa powinna znajdować się w miejscu, które korzysta z cMySQL.

Podobnie, w przykładzie użycia, który umieściłeś drogi silent, podejmujesz alternatywne działania w zależności od tego czy połączenie zakończy się powodzeniem czy też nie. Jest to oczywiście jedyne dobre miejsce na obsłużenie takiej sytuacji.

kilka uwag:

  • biedny Kooba, zaproponowałeś całkiem rozbudowany przykład.

  • proponuję przyjąć obowiązujący powszechnie zwyczaj nazywania klas wielkimi literami. (CMySQL zamiast cMySQL ... a prawdę mówiąc jeszcze lepiej po prostu MySQL).

  • bardzo rozsądnie byłoby zupełnie zrezygnować z funkcji Connect(...) a jej kod przenieść do konstruktora (przepraszam, początkowo sam to przeoczyłem).

... widzę że szybko łapiesz i jeśli chcesz poznać OOP i rozumiesz podstawowe pojęcia: dziedziczenie, polimorfizm i hermetyzacja to jest taka książka: "Wzorce Projektowe - projektowanie zorientowane obiektowo" Shalloway, Trott -przeczytanie jej na początku nauki z OOP to eksperyment nie dla mięczaków.

Poznałbyś podstawy UML, programowanie obiektowe w rozwiązywaniu typowych sytuacji i podstawy języka Java (który jest łatwym językiem, często wykładanym na pierwszym roku).

Jeśli jesteś zainteresowany takim eksperymentem, to spróbuję cię wesprzeć w trudnych momentach odpowiadając na różne pytania - dane kontaktowe na stronie: http://kapustka.net

0

Dziękuję za odpowiedź. Znowu zapaliło się następne światełko i pokazują się nowe kontury. Masz rację - to obiekt używający obiektu klasy MySQLpowinien kontrolować sytuację w przypadku niepowodzenia. Kiedyś napisałem też klasę do obsługi MySQL która miała własną kontrolę błędów na takiej zasadzie, że jeśli jakaś metoda zwróciła błąd, to każde wywołanie następnej zależnej od działania poprzedniej od razu zwracało false. Np jeśli nie powiodło się mysql_select_db to medoda Query już na początku zwracała false bez wykonywania właściwego kodu. Co o tym sądzisz?
Jeśli chodzi o Javę to zostałem skutecznie zrażony do niej na poprzedniej i obecnej uczelni, ale dziś postanowiłem sobie, że chcę się jej nauczyć - nie wiem co mi z tego wyjdzie.
BTW - oglądałeś swoją stronę pod inną przeglądarką niż IE? Jak na człowieka z takimi umiejętnościami zdziwiłeś mnie, że strona pod Firefoxem (którego serdecznie polecam zamiast IE) rozsypuje się.

0

[będzie trochę off-topic za co przepraszam]

Powiem szczerze: w kwestii budowania stron jestem rozbity. Z jednej strony uwielbiam i nie przestaję doskonalić stylu "czystej treści" i formatowania w CSS. W taki sposób starałem się zakodować własną stronę. (Proponuję zajrzeć do źródła).

Między innymi zamiast

z atrybutem width. Właśnie tu jest powód rozjeżdżania się: IE błędnie implementuje model ramkowy.</p>

Niezgodne ze standardem i niespójne implementowanie CSS w popularnych przeglądarkach łamie mi serce. (Ostatnio czytałem o ludziach, którzy organizują publiczne demonstracje przeciwko niezgodnością przeglądarek ze standardami).

Jest sposób na obejście tego problemu (opisany w książce Zeldmana "Projektowanie serwisów WWW, standardy sieciowe"). Niestety bazuje on na niskopoziomowych sztuczkach i z tego powodu jest ryzykowny i tymczasowy.

Z drugiej strony jest używanie

W najbliższym czasie przepiszę tą stronę za pomocą

0
Kapustka napisał(a)

Tak naprawdę nie mamy tu polimorfizmu - PHP nie ma mocnej kontroli typów a jest ona wymagana w tym mechanizmie.

W gruncie rzeczy, jeśli byśmy do klas MySQL i SQLite dopisali atrybut dbConnection (który, jako wspólny, został umieszczony w nadklasie) to program zadziała bez obecności abstrakcyjnej klasy Database.

Jakie korzyści daje użycie abstrakcyjnej klasy Database ?

  • czytelne wyspecyfikowanie wspólnego interfejsu
  • zawarcie wspólnych pól (dbConnection)

A dlaczego używamy dwóch klas: MySQL i SQLite zamiast jednej (jak zaproponowałeś początkowo).

  • bardzo łatwo można dodać w przyszłości obsługę kolejnych baz danych bez konieczności modyfikowania już działającego kodu.

Obsługi nowej bazy polega na dopisaniu kolejnej klasy realizującej interfejs Database. Nie dotykamy nawet jednego wiersza już działającego i przetestowanego kodu klass MySQL i SQLite.

dzięki silent, pozdrawiam

0

Kope lat...

1 użytkowników online, w tym zalogowanych: 0, gości: 1