L'objet de ma conn PDO indéfinie dans une fonction

Eléphant du PHP | 82 Messages

09 nov. 2011, 12:23

Bonjour!

Je veux créer une fonction pour déterminer le $level d'un membre. Ce $level dépend du lieu et de l'id du lieu dans lequel on se situe.. Sauf si on est administrateur du site (dans ce cas, on est toujours admin)

Voici la fonction:
function determineLevel($ort,$ort_id){
	if (isset($_SESSION['id']))
	{
		if ($ort!=0 && $_SESSION['level']<6)
		{
			$verif_lvl = $bdd->prepare('SELECT MAX(grp_mem_status) AS status WHERE grp_mem_ort = : ort AND gpr_mem_ort_id = :id AND grp_mem_mem = :mem');
			$verif_lvl->bindValue(':ort', $ort,  PDO::PARAM_INT);
   			$verif_lvl->bindValue(':id', $ort_id,  PDO::PARAM_INT);
			$verif_lvl->bindValue(':mem', $_SESSION['id'],  PDO::PARAM_INT);
			$verif_lvl->execute();
			if ($verif_lvl->rowCount()>0)
			{
				$verif_lvl_row = $verif_lvl->fetch();
				$level=$verif_lvl_row['status'];
			}
			else
			{
				$level=1;
			}
			$verif_lvl->CloseCursor();
		} // fin ort !=0
		else
		{
			$level=(isset($_SESSION['level']))?$_SESSION['level']:1;
		}
	}
	else
	{
		$level=1;
	}
	return $level;
}
(J'ai ajouté un espace entre le : et le o dans la requête car sinon, ça ajoute un smiley :) )

Ma page est constituée de la sorte :

Au début, j'include ma page connexion.php
Ensuite j'include mon debut.php
Dans ce debut.php, il y a la page function.php (qui contient la fonction en question).

Mais lorsque je le lance
$level=determineLevel($ort, $ort_id);
avec un compte standard (non admin, donc il doit faire la requete SQL), j'obtiens le message d'erreur suivant:

Code : Tout sélectionner

Notice: Undefined variable: bdd in C:\wamp\www\collaide\include\functions.php on line 86
Cependant, ma connexion a la bdd est parfaitement établie. Car si je fais une requête dans ma page en question, tout ce passe bien. C'est juste, lorsque je détermine la function dans mon ficher function.php... Pourtant il se situe bien dans le fichier debut.php qui se situe lui, bien après mon include du fichier connexion.php...

Merci d'avance!

ViPHP
xTG
ViPHP | 7331 Messages

09 nov. 2011, 13:50

Elle est établie mais pas dans ton objet. ;)
Soit tu passes la variable $bdd en argument de ta fonction, soit tu la récupères en la déclarant comme étant globale (global $bdd; dans ta fonction), soit tu étends la class PDO pour en faire un singleton.

Eléphant du PHP | 82 Messages

09 nov. 2011, 14:51

Ah, ok, je crois comprendre!

Merci beaucoup pour ta réponse, je ne suis pas encore vraiment au point en POO..

Je pense que je vais la passer en argument, donc ça sera $level=determineLevel($ort, $ort_id, $bdd); ?? ça me parait le plus simple non?

Quel solution utiliserais tu?

Merci beaucoup

ViPHP
ViPHP | 2577 Messages

09 nov. 2011, 15:10

Bonjour,

ajouter 1 lignes dans ta fonction me semble plus simple
function determineLevel($ort,$ort_id){
        global $bdd;
        if (isset($_SESSION['id']))
...
En ajoutant un paramètre lors de l'appel de cette fonction, tu peux avoir le même problème de portée de la variable $bdd.

Edit : Il va de soi que si la connexion est faite dans une fonction, il faudra également ajouter "global $bdd;" dans cette fonction.

Eléphant du PHP | 82 Messages

09 nov. 2011, 15:14

Merci beaucoup à toi pour tes réponse très précise :)

Je vais pouvoir avancer grâce à toi!

Texicitys

ViPHP
xTG
ViPHP | 7331 Messages

09 nov. 2011, 15:17

Quel solution utiliserais tu?
Un singleton, c'est selon moi le moyen le plus propre de le faire. :)

Eléphant du PHP | 82 Messages

09 nov. 2011, 15:23

Ah oui, je viens de voir, une singelton pour ma connexion à la bdd à l'air interessant, cependant, je ne sais pas du tout comment procéder, donc je pense que je vais mettre global dans la function ça me parait plus simple

Eléphant du PHP | 82 Messages

09 nov. 2011, 15:27

Bonjour,

ajouter 1 lignes dans ta fonction me semble plus simple
function determineLevel($ort,$ort_id){
        global $bdd;
        if (isset($_SESSION['id']))
...
En ajoutant un paramètre lors de l'appel de cette fonction, tu peux avoir le même problème de portée de la variable $bdd.

Edit : Il va de soi que si la connexion est faite dans une fonction, il faudra également ajouter "global $bdd;" dans cette fonction.

Ok ok, donc ici, j'ajoute global $bdd après la ligne: $bdd = new PDO... ?
try
{
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    $bdd = new PDO('mysql:host=127.0.0.1;dbname=nombase', 'root', '', $pdo_options);
	$bdd->exec('SET NAMES utf8');
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}
Merci

Eléphant du PHP | 82 Messages

09 nov. 2011, 15:30

Ahhh non, si j'ai bien compris je ne dois rien mettre dans ma connexion à la bdd vu que ce n'est pas dans une fonction..

ViPHP
ViPHP | 2577 Messages

09 nov. 2011, 16:06

Ahhh non, si j'ai bien compris je ne dois rien mettre dans ma connexion à la bdd vu que ce n'est pas dans une fonction..
Tout à fait

C'est ce que l'on appelle la portée des variables. Dans une fonction les variables ne concernent que la fonction à moins que l'on précise le contraire. Cela permet de ne pas modifier involontairement une variable extérieure à la fonction et qui aurai le même nom.

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

09 nov. 2011, 16:18

il faut que tu revois la portée des variables :)

si dans ton script tu a
<?php
$bdd = ' ..'; // cette variable est globale au script, donc utilisable partout dans le script
// sauf dans des fonctions / classe qui sont "étanches" à ce qu'il y a autour ;)

function truc() {
$bdd = 'machin'; // une autre variable totalement différente de la $bdd du dessus
}

function chose () {
global $bdd; // on indique que l'on va utiliser une variable qui s'appelle $bdd et qui est globale au script
// on utilise donc la variable définie au début
}
?>
Pour ce qui est du singleton, en gros, c'est l'art de rendre le constructeur de la classe privé et que donc on ne peux l'instancier par un $var = new maclasse();
on va aussi lui ajouter une méthode, dite statique qui va permettre de récupérer une instance de l'objet ;)

par exemple
<?php
class spdo {
    
    private static $pdoInstances = array(); // les différents instance en fonction du dsn
    private function __construct() {
        ;
    }
    
    public static function getInstance($dsn, $user,$passwd){
        if (!isset(self::$pdoInstances[$dsn])){
            try {
                self::$pdoInstances[$dsn] = new PDO($dsn, $user, $passwd);
            }
            catch (PDOException $e) {
                throw new Exception($e->getMessage(),$e->getCode(),$e->getPrevious());
            }
        }
        return self::$pdoInstances[$dsn];
    }
}

?>
cette classe ne peux pas être appelé avec classique $v = new $spdo();
on va faire
$pdo = spdo::getInstance(dsn,$user,$passwd);
et la $pdo va contenir une instance de la classe PDO.

Le truc c'est que si tu fait cela plusieurs fois dans ton script (donc plusieurs getinstance) tu n'aura pas plusieurs instance de la classe mais toujours la même et donc pas plusieurs connexion à ton sgbd.

cette est classe est multiton pas un singleton. La différence ? c'est qu'avec un singleton je ne peux avoir qu'une seul instance de la classe, quelque soit les paramètres.
la j'ai la possibilité d'avoir plusieurs instance de la classe pour des "dsn" différents. donc la en gros pour des connexion différente, par exemple une connexion à mysql, une à un serveur oracle, une à un serveur msql etc etc.
ceci ne pourrait être possible avec un singleton.

comment ça marche ?
<?php
class spdo {
    // un tableau "privé qui va contenir les différentes instance de la classe
    private static $pdoInstances = array(); 
// on définit le constructeur comme privé donc pas new spdo() possible
    private function __construct() {
        ;
    }
    // cette méthode est sstatique on ne pourra l'utiliser que comme ceci : spdo::getInstance()
    public static function getInstance($dsn, $user,$passwd){
        if (!isset(self::$pdoInstances[$dsn])){// si dans $pdoInstances je n'ai pas déja un index qui correspond à $dsn
// on créer une instance de pdo que l'on met dans $pdoInstances[$dsn]
            try {
                self::$pdoInstances[$dsn] = new PDO($dsn, $user, $passwd);
            }
            catch (PDOException $e) {
                throw new Exception($e->getMessage(),$e->getCode(),$e->getPrevious());
            }
        }
// on retourne l'instance
        return self::$pdoInstances[$dsn];
    }
}

?>
des explications ici surement plus claire.
il y a aussi d'autres patrons de conceptions ;)

bonne lecture


@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 82 Messages

14 nov. 2011, 12:42

Merci à vous tous pour ces explications. Ça fonctionne parfaitement maintenant!

Merci