Newsgroup: it.comp.www.php
Titolo: [Codice utilizzabile] - Piccolo wrapper MySql

Vorrei un piccolo giudizio su alcune classi che sto programmando.
Vi posto un piccolo esempio (astrazione DB) con MySQL.
Queste classi dovranno poi essere usate da altri componenti per l'accesso ai
dati.
Aspetto giudizi e consigli.
<?php
    /********************************************************/
    /*  Progetto: Libreria ATCL                           */
    /*  Classe: Sql                                         */
    /*  Autore: Domenico Testa                              */
    /*  Versione: 1.0.3                                     */
    /*  Ultima revisione: 15/05/2002                        */
    /*  Descrizione: classe astratta per l'accesso ai dati  */
    /*               tramite SQL                            */
    /*  Dipendenze: Nessuna                                 */
    /*                                                      */
    /********************************************************/
    //Definizione dei simboli
    define("SQL_OBJ", "");
    define("SQL_VERSION", "1.0.3");
    $LIB_NAME = "Tryton SQL Class Library";
    $LIB_VERSION = "1.0.3";
    //Definizione della classe SQL
    class Sql
    {
        //Host remoto o nome origine dati
        var $host;
        //Nome utente per l'autenticazione
        var $username;
        //Password per l'autenticazione
        var $password;
        //Nome del database o del catalogo iniziale
        var $database;
        //Buffer per le query
        var $commandText;
        //Restituisce l'host o il nome origine dati
        function get_host()
        {
            return $this->host;
        }
        //Imposta l'host o il nome origine dati
        function set_host($strHost)
        {
            $this->host = $strHost;
        }
        //Restituisce il nome utente per l'autenticazione
        function get_username()
        {
            return $this->username;
        }
        //Imposta il nome utente per l'autenticazione
        function set_username($strUsername)
        {
            $this->username = $strUsername;
        }
        //Restituisce la password per l'autenticazione
        function get_password()
        {
            return $this->password;
        }
        //Imposta la password per l'autenticazione
        function set_password($strPassword)
        {
            $this->password = $strPassword;
        }
        //Restituisce il nome del database o del catalogo iniziale
        function get_database()
        {
            return $this->database;
        }
        //Imposta il nome del database o del catalogo iniziale
        function set_database($strDatabase)
        {
            $this->database = $strDatabase;
        }
        //Restituisce il comando SQL corrente
        function get_commandText()
        {
            return $this->commandText();
        }
        //Imposta il comando SQL corrente
        function set_commandText($strQuery)
        {
            $this->commandText = $strQuery;
        }
        //Sinonimo di get_commandText [DEPRECATO]
        function get_query()
        {
            return $this->commandText;
        }
        //Sinonimo di set_commandText [DEPRECATO]
        function set_query($strQuery)
        {
            $this->commandText = $strQuery;
        }
        //METODO_PRIVATO: Visualizza un errore generato dalla classe
        function _err_feedBack($strError)
        {
            global $LIB_NAME, $LIB_VERSION;
            echo("<b>".$LIB_NAME." ".$LIB_VERSION." [Errore:]</b> -
".$strError."<BR>");
        }
        //Costruttore
        function Sql()
        {
            //Accede in maniera opzionale alle seguenti variabili globali
            //per l'inizializzazione dell'oggetto.
            global $HOST, $USERNAME, $PASSWORD, $DATABASE, $COMMANDTEXT;
            $this->set_host($HOST);
            $this->set_username($USERNAME);
            $this->set_password($PASSWORD);
            $this->set_database($DATABASE);
            $this->set_commandText($COMMANDTEXT);
            //Restituisce vero se è stato inizializzato automaticamente
almeno l'host
            return (strlen($this->host)) ? true : false;
        }
        //Funzioni da definire nelle classi specializzate
        function connect()                  { }
        function close()                    { }
        function execute($strSql="")        { }
        function fetch_array()              { }
        function fetch_row()                { }
        function num_rows()                 { }
        function num_fields()               { }
        function field_name($intIndex)      { }
        function affected_rows()            { }
        function free_result()              { }
        function create_db($strDbName)      { }
        function drop_db($strDbName)        { }
        function error()                    { }
        //Funzioni sinonimo o deprecate od opzionali
        function fetch_object()             { }
        function query($strSql="")          { }
  }
?>
<?php
    /********************************************************/
    /*  Progetto: Libreria ATCL                             */
    /*  Classe: Myql                                        */
    /*  Autore: Domenico Testa                              */
    /*  Versione: 1.0.3                                     */
    /*  Ultima revisione: 15/05/2002                        */
    /*  Descrizione: classe wrapper alle chiamate API di    */
    /*               MySQL.                                 */
    /*  Dipendenze: Eredita direttamente da Sql. Necessita  */
    /*              della path della libreria per funziona_ */
    /*              re a run-time                           */
    /*                                                      */
    /********************************************************/
    //Definizione dei simboli
    define("MYSQL_OBJ", "");
    define("MYSQL_VERSION", "2.1");
    //Inclusione della path delle librerie
    require_once("lib.inc");
    //Inclusione della classe madre
    require_once($_LIB_PATH."Sql/Sql.obj");
    //Definizione della classe MysQL
    class Mysql extends Sql
    {
        //Handle per il link al server MySQL
        var $conn;
        //Buffer dei risultati
        var $result;
        //Costruttore
        function Mysql()
        {
            //Chiamata al costruttore della classe base
            $this->Sql();
        }
        //Restituisce il numero di righe intaccate dall'ultima query
        function affected_rows()
        {
            return mysql_affected_rows($this->conn);
        }
        //Crea un database (vuoto) di nome $strDbName
        function create_db($strDbName)
        {
            if (!mysql_create_db($strDbName, $this->conn))
            {
                //Errore: impossibile creare il database specificato
                $this->_err_feedBack("Impossibile creare il database
".$strDbName." : controllare i diritti di accesso all'host");
                return false;
            }
            else return true;
        }
        //Elimina il database $strDbName
        function drop_db($strDbName) {
            if (!mysql_drop_db($strDbName))
            {
                //Errore: impossibile cancellare il database specificato
                $this->err_feedBack("Impossibile eliminare il database
".$strDbName." : controllare che il database esiste oppure di possedere i
giusti diritti di accesso all'host");
                return false;
            }
            else return true;
        }
        //Prova a connettersi all'host specificato. Restituisce un reference
al data-link
        function connect()
        {
            if(!$this->conn = mysql_connect($this->host, $this->username,
$this->password))
            {
                $this->_err_feedBack("Connessione con l'host ".$this->host."
fallita");
                return false;
            }
            //Falso se la connessione è fallita
            return $this->conn;
        }
        //Chiude la connessione (se è aperta)
        function close()
        {
            if(!$this->conn) return false;
            return mysql_close($this->conn);
        }
        //Esegue un comando SQL che può essere passato direttamente come
argomento del
        //metodo oppure impostato in precedenza con il metodo
set_commandText().
        //Nota: non viene eseguito alcun controllo sintattico dal metodo.
        function execute($strSql="")
        {
            //Prova a selezionare il database
            if (!mysql_select_db($this->database, $this->conn))
            {
                //Errore: impossibile trovare il database specificato
                $this->_err_feedBack("Impossibile eseguire la query.
Database non specificato o inesistente.");
                return false;
            }
            //Se è stata passata una query SQL la esegue direttamente
            //altrimenti utilizza quella in memoria
            if(strlen($strSql))
            {//Query specificata come parametro del metodo
                $this->result = mysql_query($strSql, $this->conn);
                $this->commandText = $strSql;
            }
            else
            {
                //Controlla che sia stato specificato un comando SQL
                if (!strlen($this->commandText))
                {
                    //Errore: nessuna query SQL specificata
                    $this->_err_feedBack("Nessuna query SQL specificata per
l'azione richiesta.");
                    return false;
                }
                else $this->result = mysql_query($this->commandText,
$this->conn);
            }
            //Chiama l'eventuale avviso di errori
            $this->error();
            //Restituisce la variabile result come da API mysql_query()
            return $this->result;
        }
        //Sinonimo di execute() [DEPRECATO]
        function query($strSql="")
        {
            return $this->execute($strSql);
        }
        //In caso si siano verificati degli errori mostra un avviso
all'utente
        function error()
        {
            if ($longMysqlErrNo = mysql_errno())
            {
                $this->_err_feedBack("Si sono verificati degli errori
nell'esecuzione della query: \"".$this->commandText."\".<br>Errore MySql
(".$longMysqlErrNo.") ".mysql_error());
            }
        }
        //Estrae una riga dal buffer dei risultati accessibile come array
associativo, numerico
        //o in entrambi i modi.
        //Restituisce falso se non ci sono risultati (o se si è alla fine
del recordset)
        function fetch_array()
        {
            if($this->result) return mysql_fetch_array($this->result);
            else return false;
        }
        //Estrae una riga dal buffer dei risultati accessibile come oggetto
php (struttura senza metodi)
        //Restituisce falso se non ci sono risultati (o se si è alla fine
del recordset)
        function fetch_object()
        {
            if($this->result) return mysql_fetch_object($this->result);
            else return false;
        }
        //Estrae una riga dal buffer dei risultati accessibile con indici
numerici.
        //Restituisce falso se non ci sono risultati (o se si è alla fine
del recordset)
        function fetch_row()
        {
            if($this->result) return mysql_fetch_row($this->result);
            else return false;
        }
        //Libera le risorse svuotando il buffer dei risultati.
        //Restituisce falso se non ci sono risultati in memoria o in caso di
fallimento.
        function free_result()
        {
            if($this->result) return mysql_free_result($this->result);
            else return false;
        }
        //Restituisce il numero di righe del recordset corrente.
        function num_rows()
        {
            if($this->result) return mysql_num_rows($this->result);
            else return false;
        }
        //Restituisce il numero di campi (colonne) in un recordset
        function num_fields()
        {
            if($this->result) return mysql_num_fields($this->result);
            else return false;
        }
        //Restituisce il nome del campo (colonna) rispondente all'indice
passato come argomento
        function field_name($intIndex)
        {
            if ($intIndex >= $this->num_fields)
            {
                //Errore: Indice fuori dall'intervallo
                $this->error("Indice di colonna fuori dal campo");
                return false;
            }
            else return mysql_field_name($this->result, $intIndex);
         }
    }
?>

        var $host;
Suggerisco (oh, a me mi garba l'array, e allora? :-) ):
	$classVars = array(
		'host'		=>	'',
		'username	=>	'',
		'@query'	=>	'commandText',
		...
	);
	// Con poco sforzo si puo' convertirla per prendere dei vettori:
	//  set(array('host','user'),array('localhost','lserni'));
	// oppure meglio ancora una lista di parametri variabile...?
	function set($var, $value)
	{
		if (!isset($this->classVars[$var]))
		{
			if (isset($this->classVars["@$var"]))
			{
				// Deprecated
				$var = $this->classVars["@$var"];
			}
			else
			{
				...
				return -1;
			}
		}
		$this->classVars[$var] = $value;
		return 0;
	}
	function get($var)
	{
		...
	}
Leonardo

 Vi posto un piccolo esempio (astrazione DB) con MySQL.
innanzi tutto ti faccio i miei complimenti per il post.
è rarissimo trovare gente che posta il proprio codice per il gusto di farlo 
e di essere apprezzati/criticati.
l'idea di base (astrazione db) secondo me è buonissima (e più volte ci ho 
pensato ma non ho mai iniziato per pirgrizia, perché, se si vuole fare 
bene, la pensavo come segue.
se si vogliono astrarre N db, bisogna fare un merge delle funzioni 
disponibili per ogni db.
poi, bisognerebbe decidere una delle due:
1 - creare metodi per tutte le funzioni, ma a questo punto li devi gestire 
con eccezioni, per esempio:
nella classe mysql dovrai avere un metodo "commit" che ritorna "funzione 
non supportata dal dbms"
e nella classe Oracle dovresti avere una "select_db" che ritorna la stessa 
cosa (oracle non funziona a db).
a questo punto ti ritroveresti a dover sapere a priori su che db andrai a 
lavorare e questo ti rende inutile tutto il lavoro.
oppure
2 - decidi di lavorare con metodi sql standard quindi avrai:
connect, query, fetch.
a discrezione del "creatore delle classi" decidere come implementare altri 
metodi comuni a tutti i db con + o meno codice da scrivere.
(esempio posso creare per oracle un metodo fetch_object, che non ha di suo, 
in modo da rimanere compatibile con gli altri fetch_objects degli altri 
db..)
e così via.
è un lavoro abbastanza lungo e da pensarci su, in modo da essere davvero 
"trasparente" per l'utilizzatore. altrimenti serve a poco!
per questo non ho mai iniziato a farlo. per adesso mi limito a scegliere a 
priori il dbms e a scrivere codice ad hoc oppure a scrivere funzioni 
personalizzate per ogni db ma che sono già ottimizzate a livello di query 
per i db su cui vorrò usare l'applicazione.
non so se mi sono spiegato bene
:-)
ciao