Bonjour j'ai une function qui doit se connecter à ma bdd via ma function getDB, j'utiliser pour ça le mots $this mais sur mon navigateur ont m'indique que le mots cké $this n'est pas bon. Du coup j'ai beau essayer plusieurs syntaxes mais ça ne fonctionne jamais ... , Avez vous une solution ?

je suis ce tuto : https://grafikart.fr/tutoriels/injection-571


public static function getTable($name){

$class_name = '\\App\\Table\\' . ucfirst($name) . 'Table';

 return new $class_name($this->getDB());
}

Ce que j'obtiens

Erreur fatale : Erreur non détectée : Utilisation de $this lorsqu'il n'est pas dans le contexte de l'objet dans C:\xampp\htdocs\gra\app\App.php:30 Stack trace : #0 C:\xampp\htdocs\gra\public\index.php (11) : App\App::getTable('Posts') #1 {main} lancé dans C:\xampp\htdocs\gra\app\App.php à la ligne 30

9 réponses


Hello :)

Mmmh on dirait un problème de type... Fais voir ton autoloader et ta classe appelée complète?

/////////////////////// Mon autoloader .php

namespace App;

/**
 * Class Autoloader
 * @package Tutoriel 
 */

class Autoloader {

/**
 * Enregistre mon autoloader 
 */

 static function register(){
    spl_autoload_register(array(__CLASS__, 'autoload'));
 }

/**
 * Inclue le fichier correspondant à notre classe
 * @param $class string Le nom de la classe à charger 
 */

 static function autoload($class){
    if (strpos($class,__NAMESPACE__ . '\\') === 0){
        $class = str_replace(__NAMESPACE__ . '\\', '', $class);
        $class = str_replace('\\', '/', $class);
        require __DIR__  . '/' . $class . '.php';
    }
 }

}

/////////////////////// Mon fichier App.php

namespace App;

class App {

public $title = 'Mon super site';
private static $_instance;
private static $db_instance;

public static function getInstance(){
    if(is_null(self::$_instance)){
        self::$_instance = new App();
    }

    return self::$_instance;
}

public static function getTable($name){

$class_name = '\\App\\Table\\' . ucfirst($name) . 'Table';

    return new $class_name($this->getDB());
}

public function getDB(){

    $config = Config::getInstance();

    if(is_null($this->db_instance)){
$this->db_instance =  new MYSQLDatabase($config->get('db_name'), $config->get('db_user'), $config->get('db_pass'), $config->get('db_host'));
    }

    return $this->db_instance;

}

Okay voila le problème, tu utilises this pour acceder à des propriétés statiques, PHP n'accepte pas ça, il faut que tu vires les attributs static, en gros dans PHP c'est du tout ou rien, soit tu mets des static PARTOUT, soit tu n'en mets pas (et bon mieux vaut pas en mettre, le static va te pousser à la mauvaise pratique)

Ensuite si malgré tout tu veux mettre du static partout, alors tu ne peux pas utiliser $this->, il faut utiliser self:: puis adapter le code

Donc j'enleve les static de tout mes fichiers ? Je suis le tuto de grafikart sur Injection de dépendances et il ne fait pas ça.

Alors, le tuto est extrêmement ancien donc ptet qu'il y a eu du nouveau, eeeet le static ce n'est pas une injection de dépendance :p

Et yep tu fera un new au lieux d'invoquer un static plus propre ^^

Oui je sais bien que le static n'est ps une injection , le probléme c'est que dans ma fun tion quan dont fait new la db doit se connecter en meme temps

Mmmh ce qu'il faudrait faire c'est créer une nouvelle classe Database, et mettre la function getDb

Dans ton index tu fais un new Database, tu t'y connectes, et tu enregistres ça dans une variable, en principe faut faire ça, c'est un principe du SOLID (si tu connais pas le SOLID, regardes des vidéos dessus, je crois que Grafikart en a fait une, c'est la bible du dev php :p)

Enfaite je sais déja le faire en solid mais mon but est d'apprend les injections

Alors, le fait de mettre une instance DB dans l'App c'est pas très "S" de SOLID, ta class App fait tout :p

Pour faire de l'injection, il faudrait faire un truc dans ce style:

// class Database

namespace Database

class Database {
    protected MYSQLDatabase $db_instance;
    protected App $instance;

    public function getInstance(){
        return $this; // En vrai ça revient à faire ça, le new faut le faire dans index.php
    }

    public function getTable($name){
        $class_name = '\\App\\Table\\' . ucfirst($name) . 'Table';
        return new $class_name($this->getDB());
    }

    protected function getDB(){
        $config = Config::getInstance();

        if(is_null($this->db_instance)){
            $this->db_instance =  new MYSQLDatabase($config->get('db_name'), $config->get('db_user'), $config->get('db_pass'),  
            $config->get('db_host'));
        }

        return $this->db_instance;
    }
}

// class App qui inject Database
namespace App;

use Database;

class App {
    public $title = 'Mon super site';
    protected $database; // juste parce que protected c'est mieux que private :p

    public function __construct(Database $database) // L'injection se passe ici
    {
        $this->database = $database;
    }
}

// index.php

$app = new App(new Database()); // Alors c'est pas le top, mais c'est la meilleure façon de faire sans librairies, si tu peux utiliser une lib, tu peux init composer (du coup tu pourras virer ton autoloader :p) et installer par exemple ça: https://github.com/auraphp/Aura.Di

Bon mainteant en vrai la class App m'a l'air d'être un manager global, le mieux ça aurait été de faire une class Database, une class HomePage, et une class App, dans ta class HomePage tu places ton titre "mon super site", et dans Database bah tout ce qui est lié à la DB, et tu injectes le tout dans la class App qui va piloter ces deux class, et dans un second temps tu injectera un router pour injecter dynamiquement un HomePage ou un AboutPage dans ta class App, pour cela faudra apprendre les "interfaces php", mais c'est dans un second temps, t'embrouilles pas la tête avec ça pour l'instant :p