0
votes

PHP PDO pour créer un objet d'une classe avec fetchObject

J'essaye de créer un objet "Utilisateur" dans ma classe "Utilisateur" basé sur les propriétés que j'ai stockées dans ma base de données, auxquelles j'utilise PDO pour me connecter.

J'ai recherché certaines pages sur Google et j'ai constaté que la plupart des gens utilisent la méthode fetchObject pour cela. En ce moment, j'essaye d'utiliser ceci pour créer un objet de cette classe actuelle mais j'obtiens toujours l'erreur:

Erreur fatale: Uncaught ArgumentCountError: Trop peu d'arguments pour la fonction User :: __ construct (), 0 passé et exactement 11 attendus dans ...

Tout le monde continue d'utiliser celui-ci sur le Web mais je n'arrive pas à trouver leurs constructeurs, car ils n'ont peut-être aucun attribut à recevoir.

Mon code actuel est le suivant:

public static function createUserBySQL($id)
    {
        $stmt = BD::getConnection()->prepare("SELECT * FROM user WHERE username = ?");
        $stmt->execute([$id]);
        $user = $stmt->fetchObject(__CLASS__);
        var_dump($user);
        return $user;
    }

Cela peut être facile à résoudre mais c'est la première fois que je fais la POO en PHP avec PDO, donc je ne connais pas encore tous les trucs et astuces pour contourner aussi facilement;)

Merci,
mikeysantana

MODIFICATION RAPIDE: Tous les attributs de l'instance "User" sont privés et je voulais le garder comme ça pour maintenir la logique du code.


3 commentaires

fetchObject() ne fonctionne pas en passant les valeurs de colonne au constructeur. Il crée l'objet, initialise toutes les propriétés des colonnes, puis appelle le constructeur sans argument.


C'est presque la seule chose décrite dans le manuel sous cette entrée: php.net/manual/en/pdostatement.fetchobject.php


fetchObject fait des choses magiques. Il définit directement les attributs de l'objet. Le constructeur ne doit attendre aucun paramètre.


3 Réponses :


1
votes

Vous devez rendre les paramètres de votre constructeur facultatifs. La documentation dit:

Lorsqu'un objet est récupéré, ses propriétés sont attribuées à partir des valeurs de colonne respectives, puis son constructeur est appelé.

Lorsque le constructeur est appelé, aucun argument n'est fourni, c'est pourquoi vous obtenez cette erreur.

Le constructeur doit vérifier si les arguments ont été fournis explicitement et ne renseigner les propriétés que lorsqu'ils le sont. Il y a quelques exemples de la façon de procéder dans la section des commentaires de la documentation ci-dessus.


0 commentaires

0
votes

Merci à tous pour votre aide.

Pour aider les futurs lecteurs de cette question, voici ma solution:

J'ai conservé la méthode "createUserBySQL" ci-dessus telle quelle, je n'ai changé que mon constructeur.

Le constructeur a maintenant tous ses attributs dans la signature facultatifs, comme ceci:

function __construct($firstname = null, $surname = null, ...)
    {
        if (func_get_args() != null){
            $this->firstname = $firstname;
            $this->surname = $surname;
            ...
        }
    }

Dans le constructeur, j'ai fait une validation pour voir si tous les arguments étaient nuls. Comme j'en avais 11, faire une instruction if pour tous serait assez ennuyeux, j'ai donc utilisé la méthode func_get_args () qui retourne un tableau avec tous les arguments passés au constructeur.

Le constructeur final ressemblerait à ceci:

function __construct($name = null, $surname = null ...)


0 commentaires

1
votes

Après quelques essais, j'ai réussi à faire fonctionner cela sans définir de valeurs par défaut dans les constructeurs ni aucune solution de contournement. La clé se trouve dans le PDO::FETCH_PROPS_LATE * et le tableau d'arguments à la fin.

La solution

$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Count", [0]); 

// Warning: Division by zero in C:\xampp\htdocs\app\Model\Post.php on line 15 INF
// Warning: Division by zero in C:\xampp\htdocs\app\Model\Post.php on line 15 INF

Exemple de travail

class Count{
        private $number5;

        function __construct($number)
            {
                $this->number5 = $number;

                print_r(10 / $this->number5); // should be 10/5, so print 2
            }
        }        
$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Post", [0,0]); 

print_r($result[0]->getId());
// 1

print_r($result);

// Array
// (
//     [0] => Post Object
//         (
//             [id:Post:private] => 1
//             [content:Post:private] => value from the db
//         )

//     [1] => Post Object
//         (
//             [id:Post:private] => 2
//             [content:Post:private] => it is working!
//         )
// )

Attention:

* Lorsque PDO::FETCH_PROPS_LATE est utilisé avec PDO::FETCH_CLASS , le constructeur de la classe est appelé avant que les propriétés soient affectées à partir des valeurs de colonne respectives.

Gardez donc à l'esprit que le constructeur sera appelé avec les valeurs d'espace réservé, pas les données de la base de données, donc cette solution n'est (absolument) pas recommandée si vous manipulez les valeurs d'entrée tout de suite dans le constructeur. Mais fonctionne bien pour simplement initialiser les propriétés de classe.

Le problème avec ça

class Post
{
    private $id;
    private $content;

    function __construct($id, $content){
        $this->id = $id;
        $this->content = $content;
    }

    public function getId(){
        return $this->id;
    }
}
$ctor_args = array(1, 'a placeholder')// pass an array of placeholder values.

$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Post", $ctor_args); 

Oui, il appelle le constructeur deux fois.


7 commentaires

Mec, si c'est ce que je pense, c'est une percée. J'espère que vous ne vous trompez pas. Va vérifier


Ah, je vois. vous venez de fournir de faux paramètres de constructeur. intelligent, mais pas vraiment ce que je pensais.


Eh bien, cela fonctionne, et c'est le plus simple d'utiliser des fonctions comme wrappers ou d'ajouter des valeurs nulles de vérification logique.


vous auriez donc pu en faire un tableau en ligne, "Post", [0,0]); Je ne sais pas pourquoi s'embêter avec une variable distincte


Oui. J'ai mis la variable juste pour insérer le commentaire après. C'est bon de savoir que cela fonctionne aussi de cette façon, je pensais qu'il avait un lien avec les accessoires ou qu'il fallait avoir une valeur unique.


C'est le problème. Il n'a aucun lien. Vous définissez d'abord de fausses valeurs, puis FETCH_PROPS_LATE les écrase. Ainsi, vous pouvez avoir votre classe instanciée de deux manières - via un appel direct en utilisant le paramètre du constructeur ou via PDO en utilisant un faux paramètre et en laissant PDO attribuer des valeurs directement aux propriétés


Je vois, si vous avez une logique à l'intérieur du constructeur, il s'exécutera avec les fausses valeurs.