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.