PHP: usare SQLite

In questo articolo vedremo come usare SQLite con PHP.

Il primo passo è verificare che l'estensione sqlite3 sia installata e abilitata. Per farlo digitiamo dalla shell:

php -m

Nella lista delle estensioni riportate dovremmo poter individuare quella che ci interessa. Quindi possiamo creare il file del database nella nostra directory di sviluppo con il seguente comando:

touch database.db

L'estensione SQLite di PHP segue l'approccio Object-Oriented a differenza di quello misto dell'estensione mysqli. Il modo migliore per sfruttare questo approccio è quello di creare una classe wrapper attorno alla classe di riferimento SQLite3.

Quando si cerca di instanziare questa classe usando come argomento il file del database appena creato, si deve anche gestire l'eventuale eccezione sollevata.

class DB {
    private $db = null;
    private $errorMessage = '';
    public function  __construct($dbName = 'database.db') {
        try {
            $this->db = new SQLite3($dbName);
        } catch(Exception $ex) {
            $this->db = null;
            $this->errorMessage = $ex->getMessage();
        }
    }
    public function getInstance() {
        return $this->db;
    }

    public function getErrorMessage() {
        return $this->errorMessage;
    }
    public function __destruct() {
        if(!is_null($this->db)) {
            $this->db->close();
        }
    }
}    

I metodi costruttore e distruttore vengono usati rispettivamente per creare una connessione al database e per chiuderla. Se viene sollevata un'eccezione, l'istanza della connessione resterà sul valore null e la proprietà errorMessage verràr popolata con il messaggio di errore corrispondente. Possiamo sfruttare questa caratteristica quando andiamo ad utilizzare la nostra classe.

require_once 'lib/DB.php';

$db = new DB();
if(is_null($db->getInstance())) {
    echo $db->getErrorMessage();
    exit(1);
}

Quando iniziamo a lavorare con un nuovo database, al suo interno non sono presenti tabelle. La prima operazione da effettuare, quindi, è la creazione delle tabelle essenziali. A questo scopo creiamo un metodo specifico di inizializzazione dei dati.

public function initDB($createStmt) {
        if(is_null($this->db)) {
            $this->errorMessage = 'Database instance is NULL.';
            return false;
        }
        $created = $this->db->exec($createStmt);
        if(!$created) {
            $this->errorMessage = 'Query failed. Reason: ' . $this->db->lastErrorMsg();
            return false;
        }
        return true;
    }

Il metodo SQLite3::exec() restituisce un valore booleano che indica il risultato dell'operazione effettuata sul database. lastErrorMsg() restituisce invece il messaggio di errore più recente a seguito del fallimento di un'operazione.

Possiamo quindi creare una tabella iniziale come segue:

$create_table_statement = <<<SQL
CREATE TABLE IF NOT EXISTS laureates (
    id INTEGER PRIMARY KEY,
    fullname TEXT NOT NULL,
    category TEXT NOT NULL,
    year INTEGER NOT NULL
);
SQL;

if(!$db->initDB($create_table_statement)) {
    echo $db->getErrorMessage();
    exit(1);
}

Possiamo quindi popolare la nostra tabella con ad esempio dei dati ricavati da un file JSON contenente i nomi, la categoria, l'anno e l'ID di vari premi Nobel. Per farlo creiamo un metodo helper per l'operazione di INSERT.

public function insert($table = '', $columns = [], $data = []) {
        $column_names = implode(',', $columns);
        $values = implode(',', $data);
        $query = "INSERT INTO $table ($column_names) VALUES ($values)";
        return $this->db->exec($query);
    }

L'inserimento consiste nell'effettuare un loop molto semplice (e volutamente non ottimizzato al fine di mostrare le operazioni in modo atomico) sull'array di dati JSON.

$dataset = json_decode(file_get_contents('laureates.json'), true);

foreach($dataset as $datum) {
    $id = intval($datum['id']);
    $name = $datum['name'];
    $category = $datum['category'];
    $year = intval($datum['year']);
    $columns = ['id', 'fullname', 'category', 'year'];
    $values = [$id, "'$name'", "'$category'", $year];
    if($db->insert('laureates', $columns, $values)) {
        echo "Inserted $name \n";
    }
}

L'estensione di PHP per SQLite supporta come le altre i prepared statements, che sono un ottimo modo di mantenere la coerenza dei dati e di prevenire potenziali problemi di sicurezza.

Supponiamo ora di voler ottenere tutti i premi Nobel per la fisica. Possiamo scrivere:

$db_instance = $db->getInstance();

$stmt = $db_instance->prepare('SELECT * FROM laureates WHERE category=:cat');

$stmt->bindValue(':cat', 'physics', SQLITE3_TEXT);
$results = $stmt->execute();

while( $row = $results->fetchArray(SQLITE3_ASSOC)) {
    var_dump($row);
}

Come si può notare, la sintassi è analoga a quella a cui siamo abituati per le estensioni che gestiscono i database MySQL.

Riferimenti

PHP: SQLite3

Torna su