8807 sujets

Développement web côté serveur, CMS

Bonjour,

PHP : je sais qu'il existe plein de bonnes raisons pour exécuter des requêtes préparées mais je m'étonne de la lourdeur de la chose, du moins de la façon dont je pratique.

Requête simple :

$requete = "SELECT orig FROM matable WHERE id=" . $id;
list ($orig) = mysqli_fetch_row (mysqli_query ($connexion, $requete)):


Requête préparée :

$requete = "SELECT orig FROM matable WHERE id= ? ";

$stmt = mysqli_prepare ($connexion, $requete);

mysqli_stmt_bind_param ($stmt, 'i', $id);

mysqli_stmt_execute($stmt);

$resultat = mysqli_stmt_get_result ($stmt);

$retour = mysqli_fetch_all ($resultat, MYSQLI_ASSOC);

$orig = $retour[0]['orig'];


On passe de 2 à 7 lignes.
La requête préparée ci-dessus est-elle possible à racourcir ?
Modifié par boteha_2 (30 Nov 2025 - 16:04)
Modérateur
Salut,

Il y a quelques années, je mettais fait un wrapper pour éviter ce genre de désagrément.

Ci dessous, je te donne le code. J'ai viré les namespace. Ce sera à toi de les remettre suivant ton contexte. J'ai seulement mis des require_once.

l'arborescence : https://www.noelshack.com/2025-49-1-1764549503-capture-d-cran-de-2025-12-01-01-37-44.png

Il n'y a pas longtemps, j'ai désinstallé MySQL de mon système. Normalement, ça devrait fonctionner. Tiens-moi au courant si tu utilises ma librairie.

index.php :

<?php
    require_once './db/FactoryDB.php';

    $params_db = [
        'driver' => 'Postgresql',
        'host' => 'localhost',
        'database' => 'blog',
        'user' => 'postgres',
        'password' => 'admin'
    ];
    $db = FactoryDB::initialize($params_db);
    // requête préparée
    $sql = "SELECT * FROM blog_post LIMIT :limit OFFSET :offset";
    $args = [
        'limit' => 1,
        'offset' => 4
    ];
    $result = $db->query($sql, $args)->fetch();
    print_r($result);
    echo '<hr>';
    // requête non préparée
    $sql = "SELECT * FROM blog_post";
    $result = $db->query($sql)->fetch();
    print_r($result);
?>


DB.php

<?php
    class DB{
        private $pdo = null;
        private $query = null;

        public function __construct($params){
            $this->pdo = new PDO($params['dns'], $params['user'], $params['password']);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }

        public function beginTransaction(){
            $this->pdo->beginTransaction();
        }

        public function commit(){
            $this->pdo->commit();
        }

        public function rollBack(){
            $this->pdo->rollBack();
        }

        public function query($sql, $params = []){
            try {
                if(count($params) > 0){
                    $this->query = $this->pdo->prepare($sql);
                    foreach($params as $key => $value){
                        $paramType = PDO::PARAM_STR;

                        if(is_int($value)){
                            $paramType = PDO::PARAM_INT;
                        } elseif(is_bool($value)){
                            $paramType = PDO::PARAM_BOOL;
                        } elseif(is_null($value)){
                            $paramType = PDO::PARAM_NULL;
                        }

                        if(is_string($key)){
                            $this->query->bindValue($key, $value, $paramType);
                        } else {
                            $this->query->bindValue($key + 1, $value, $paramType);
                        }
                    }
                    $this->query->execute($params);
                }else{
                    $this->query = $this->pdo->query($sql);
                }

                return $this;
            } catch (Exception $e) {
                error_log("Database error: " . $e->getMessage());
                return false;
            }
        }

        public function fetch(){
            return $this->query->fetchAll(PDO::FETCH_OBJ);
        }

        public function getLastInsertId(){
            return $this->pdo->lastInsertId();
        }
    }


Factory.php

<?php
    require_once './db/DB.php';
    require_once './db/Mysql.php';
    require_once './db/Sqlite.php';
    require_once './db/Postgresql.php';

    class FactoryDB{
        private static $_instance = null;

        private function __construct(){}
        private function __clone(){}


        public static function initialize($params){
            if(is_null(self::$_instance)) {
                $allowedDrivers = ['Sqlite', 'Mysql', 'Postgresql'];
                if (!in_array($params['driver'], $allowedDrivers)) {
                    throw new Exception("Driver not allowed: {$params['driver']}", 500);
                }

                if (!class_exists($params['driver'])) {
                    throw new Exception("Could not find the driver: {$params['driver']}", 500);
                }

                self::$_instance = new $params['driver']($params);
            }

            return self::$_instance;
        }
    }

Mysql.php

<?php
    require_once './db/DB.php';

    class Mysql extends DB{
        public function __construct($params){
            $args = [
                'dns'       => sprintf('mysql:host=%s;dbname=%s;charset=utf8', $params['host'], $params['database']),
                'user'      => $params['user'],
                'password'  => $params['password']
            ];
            parent::__construct($args);//, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
        }
    }

Postgreql.php

<?php
    require_once './db/DB.php';

    class Postgresql extends DB{
        public function __construct($params){
            $args = [
                'dns'       => sprintf('pgsql:host=%s;port=%s;dbname=%s', $params['host'], $params['port'] ?? 5432, $params['database']),
                'user'      => $params['user'],
                'password'  => $params['password'],
            ];
            parent::__construct($args);
        }
    }


Sqlite.php

<?php
    require_once './db/DB.php';

    class Sqlite extends DB{
        public function __construct($params){
            $pathToDatabase = $params['path'];
            if(file_exists($pathToDatabase)){
                $args = [
                    'dns'       => sprintf('sqlite:%s', $pathToDatabase),
                    'user'      => null,
                    'password'  => null
                ];
                parent::__construct($args);
            }
        }
    }

Modifié par Niuxe (01 Dec 2025 - 01:50)
Hello,

Si tu trouves que l'API PHP mysqli est trop verbeuse, tu peux essayer de d'utiliser PDO à la place.

Avec PDO, ton exemple donnerait ceci :
// Connexion à la base de données
$dbh = new PDO('mysql:host=mabasemysql.example.com;dbname=mabasededonnees', 'nom_d_utilisateur', 'mot de passe');

// Requête préparée
$stmt = $dbh->prepare("SELECT orig FROM matable WHERE id=:id");
$stmt->bindParam(':id', $mon_id);

// Exécution de la requête
$stmt->execute();

// Récupération des résultats
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);


Accessoirement PDO permet d'utiliser un certain nombre d'optimisations sympa, comme le fait de pouvoir itérer sur les résultats d'une requête un à un sans télécharger les données complètes :

$stmt->execute()
foreach ($stmt as $row) {
    print_r($row);
}

Modifié par GuillaumeBauer (01 Dec 2025 - 11:29)