Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection simple implementation

after reading this question i wonder if someone can help me understand how to implement correctly Dependency Injection with these PHP Classes:

class DBClass
{
    private $mMysqli;
    function  __construct(mysqli $database)
    {
        $this->mMysqli=$database;
    }
    function __destruct()
    {
        $this->mMysqli->close();
    }

    public function listUsers()
    {
        $query='SELECT * FROM Utente;';
        $resultset=$this->mMysqli->query($query);
        while($row = $resultset->fetch_array(MYSQLI_ASSOC)) {
            echo $row['username'];
            echo $row['pwd'];
            echo "<br />\n";
        }

    }

    public function runQuery($query)
    {
        return $resultset=$this->mMysqli->query($query);
    }

    public function getConnection()
    {
        return $this->mMysqli;
    }
}

Session class:

class Session
{
    private $_session;
    public $maxTime;
    private $database;

    public function __construct(DBClass $database)
    {
        $this->database=$database;
        $this->maxTime['access'] = time();
        $this->maxTime['gc'] = get_cfg_var('session.gc_maxlifetime');
        session_set_save_handler(array($this,'_open'),
                array($this,'_close'),
                array($this,'_read'),
                array($this,'_write'),
                array($this,'_destroy'),
                array($this,'_clean')
                );
        register_shutdown_function('session_write_close');
        session_start();
        ...
     }
}   

User Class (for details about the currently logged in user):

class User
{
    private $username;
    private $role;
    private $session;

    function __construct($session)
    {
        $this->session=$session;
        ...
    }
}

Externally:

$connection=new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE);
$database=new DBClass($connection);
$session=new Session($database);
$user=new User($session);

Is this the proper way?

like image 272
Gianluca Bargelli Avatar asked Jan 22 '23 19:01

Gianluca Bargelli


1 Answers

Yes. You are now injecting the dependencies through the constructor which provides for less coupling. You can now more easily swap out these dependencies, e.g. when UnitTesting you can replace them with Mocks.

You have still some coupling though by using the concrete DBClass as a TypeHint instead of an interface. So when you would want to use a different DBClass, it would have to be named DBClass. You could achieve more loose coupling by coding against an interface that the concrete classes have to implement instead.

To create only single instances of a class (as asked in the comments), you could either use a Singleton (like Kevin Peno suggested) or a Factory to create and keep track of if the instance has been created yet. Or use a DI Service Container, which is similar to a Factory, yet not the same thing. It creates and manages objects for you.

The Symfony Components library has a Dependency Injection Container with excellent documentation and introduction to the topic on how to further enhance DI this with Service Containers. The containers can also be used to limit instances. Check it out.

like image 189
Gordon Avatar answered Jan 28 '23 13:01

Gordon