PHP dependency injection in extended class

class, dependency-injection, extend, oop, php

Solution

I think you're really mixing up means and purposes here. The goal is never to use dependency injection per se, but to solve programming problems that you encounter with it. So let's first try and correct the dependencies between the classes and their responsibilities a little.

In my opinion, it is best to start this excercise from the application domain, start small, and then refactor if you want to introduce abstraction. At least when learning or as a thought experiment. When more experienced and when implementing the real thing, it is probably smarter to look a couple of steps ahead.

So for now I'll simply assume you're making an online game, with different users that are represented by GameUser objects, and no further than that.

The sole responsibility of the `GameUser` class should be to represent the domain data and logic, i.e.: it contains a couple of properties (let's say `username` and `score`) and methods (let's say `incrementScore`) that have to do with the application domain itself (game users). It should not be responsible for practical implementation details, most notably: how it gets persisted (written to file/db/whatever). That's why a `DatabaseLayerUser` that is responsible for storing itself is probably a bad idea. So let's start instead with a nice and clean `GameUser` domain class and use encapsulation (private properties to prevent tampering from the outside):

class GameUser {

    private $_username;
    private $_score;

    public function __construct($username, $score) {
        $this->_username = $username;
        $this->_score = $score;
    }

    public function getUsername() { return $this->_username; }
    public function getScore() { return $this->_score; }
    public function incrementScore() {
        $this->_score++;
        return $this->_score;
    }
}

We can now create a new `GameUser` (`$user = new GameUser('Dizzy', 100);`), but we cannot persist it. So we need some kind of repository where we can store these users and fetch them again later. Let's call it just that: the `GameUserRepository`. This is a service class. Later when there is more than one type of domain object and repository, we can create a `DatabaseLayer` class that will group these and/or act as a facade, but we start small now and will refactor later.

Once again, the responsibility of the `GameUserRepository` class is to allow us to fetch and store `GameUser` objects, and to check if a profile for a given username exists. In principle, the repository could store the `GameUser` objects in a file or somewhere else, but for now, we're making making the choice here to persist them in a SQL database (start small, refactor later, you get it.)

The responsibility of the `GameUserRepository` is not management of the database connection. It will however need a database object so it can pass the SQL queries to it. So it delegates the responsibility of setting up the connection and actually executing the SQL queries it will create.

Delegation rings a bell. Dependency injection comes into play here: we will inject a PDO database object (service). We'll inject it in the constructor (i.e. constructor DI as opposed to setter DI). It is then the responsibility of the caller to figure out how to create the PDO service, our repository really couldn't care less.

class GameUserRepository {

    private $_db;

    public function __construct(PDO $db) {
        $this->_db = $db;
    }

    public function profileExists($username) {
        try {
            $PDOQuery = ('SELECT count(1) FROM userprofile_upl WHERE uid_upl = :uid');
            $PDOStatement = $this->dbh->prepare($PDOQuery);
            $PDOStatement->bindParam(':uid', $username);
            $PDOStatement->execute();
            return $PDOStatement->fetchColumn() >0;
        } catch(PDOException $e) {
            throw  new Exception('Failed to check if profile exists for '. $username, 0, $e);
        }
    }

    public function fetchGameUser($username) { ... }
    public function storeGameUser(GameUser $user) { ... }
}

To answer Q1 & Q2 in one go: `function __construct(PDO $db)` simply expresses a type constraint: PHP will check that the `$db` parameter value is a PDO object. If you're trying to run `$r = new GameUserRepository("not a PDO object");`, it will throw an error. The `PDO` type constraint has nothing to do with dependency injection.

I think you're confusing this with the functionality of DI frameworks that actually inspect the constructor signature at run-time (using reflection), see that a PDO-type argument is needed, and then indeed create such an object automagically and pass it to the constructor when creating the repository. E.g. the Symfony2 DI bundle can do this, but it has nothing to do with PHP itself.

Now we can run code like this:

$pdo = new PDO($connectionString, $user, $password);
$repository = new GameUserRepository($pdo);
$user = $repository->fetchGameUser('Dizzy');

But this begs the question: what is the best way to create all these objects (services), and where do we keep them? Surely not by just putting the above code somewhere and using global variables. These are two clear responsibilities that need to be located somewhere, so the answer is that we create two new classes: the `GameContainer` class and the `GameFactory` class to create this container.

The responsibility of the `GameContainer` class is to centralize the `GameUserRepository` service with other services that we'll create in the future. The responsibility of the `GameFactory` class is to set up the `GameContainer` object. We'll also create a `GameConfig` class to configure our `GameFactory`:

class GameContainer {
    private $_gur;
    public function __construct(GameUserRepository $gur) { $this->_gur = $gur; }
    public function getUserRepository() { return $this->_gur; }
}

class GameConfig { ... }

class GameFactory { 
    private $_config;

    public function __construct(GameConfig $cfg) {
        $this->_config = $cfg;
    }

    public function buildGameContainer() {
        $cfg = $this->_config;
        $pdo = new PDO($cfg->read('db.dsn'), $cfg->read('db.user'), $cfg->read('db.pw'));
        $repository = new GameUserRepository($pdo);
        return new GameContainer($repository);
    }
}

We can now imagine a `game.php` application with basically the following code:

$factory = new GameFactory(new GameConfig(__DIR__ . '/config.php')); 
$game = $factory->buildGameContainer();

One crucial thing is still missing however: the use of interfaces. What if we want to write a `GameUserRepository` that uses an external web service to store and fetch `GameUser` objects? What if we want to provide a `MockGameUserRepository` with fixtures to facilitate testing? We can't: our `GameContainer` constructor explicitly demands a `GameUserRepository` object as we have implemented it using the `PDO` service.

So, now is the time to refactor and extract an interface from our `GameUserRepository`. All consumers of the current `GameUserRepository` will now have to use the `IGameUserRepository` interface instead. This is possible thanks to dependency injection: references to `GameUserRepository` are all just used as type constraints that we can replace by the interface. It would not be possible if we hadn't delegated the task of creating these services to the `GameFactory` (which will now have the responsibility to determine an implementation for each service interface.)

We now get something like this:

    interface IGameUserRepository { 
        public function profileExists($username);
        public function fetchGameUser($username);
        public function storeGameUser(GameUser $user);
    }

    class GameContainer {
        private $_gur;

        // Container only references the interface:
        public function __construct(  IGameUserRepository $gur  ) { $this->_gur = $gur; }
        public function getUserRepository() { return $this->_gur; }
    }        

    class PdoGameUserRepository implements IGameUserRepository {
        private $_db;

        public function __construct(PDO $db) {
            $this->_db = $db;
        }

        public function profileExists($username) {...}
        public function fetchGameUser($username) { ... }
        public function storeGameUser(GameUser $user) { ... }
    }

    class MockGameUserRepository implements IGameUserRepository {

        public function profileExists($username) {
            return $username == 'Dizzy';
        }

        public function fetchGameUser($username) { 
            if ($this->profileExists($username)) {
                return new GameUser('Dizzy', 10);
            } else {
                throw new Exception("User $username does not exist.");
            }
        }

        public function storeGameUser(GameUser $user) { ... }
    }

    class GameFactory { 
        public function buildGameContainer(GameConfig $cfg) {
            $pdo = new PDO($cfg->read('db.dsn'), $cfg->read('db.user'), $cfg->read('db.pw'));

            // Factory determines which implementation to use:
            $repository = new PdoGameUserRepository($pdo);

            return new GameContainer($repository);
        }
    }

So this really puts all pieces together. We can now write a `TestGameFactory` injecting the `MockGameUserRepository`, or, better still, extend `GameConfig` with a "env.test" boolean and have our existing `GameFactory` class decide whether to construct a `PdoGameUserRepository` or `MockGameUserRepository` based on that.

The connection with DI practices should now be clear as well. The `GameContainer`, of course, is your DI container. The `GameFactory`, is the DI container factory. It is these two that are implemented with all bells and whistles by DI frameworks such as the Symfony2 DI bundle.

You can indeed imagine extending the factory and its config up to the point where all services are completely defined in an XML file, including their implementation class names:

<container env="production">
    <service name="IGameUserRepository" implementation="PdoGameUserRepository">
        <connectionString>...</connectionString>
        <username>...</username>
        <password>...</password>
    </service>
</container>

<container env="test">
    <service name="IGameUserRepository" implementation="MockGameUserRepository"/>
</container>

You can also imagine generalizing the `GameContainer` so that services are fetched like `$container->getService('GameUserRepository')`.

As for passing constructor arguments to parent classes in PHP (which has little to do with DI, except that it'll be needed sooner or later if you use constructor injection), you can do this as you suggest yourself:

class A {
    private $_someService;
    public function __construct(SomeService $service) { $this->_someService = $service; }
}

class B extends class A {
    private $_someOtherService;

    public function __construct(SomeService $service, SomeOtherService $otherService) { 
        parent::__construct($service);
        $this->_someOtherService = $otherService;
    }
}

$b = new B(new SomeService(), new SomeOtherService());

But you'll have to stay away from the private constructors. They reek of singletons.

Problem

I'm just getting to grips with `OOP`, so sorry if this question seems a little all over the place, its how my head is feeling right now. I have looked at constructors in the PHP docs but it does not seem to cover dependency injection. I have a class called DatabaseLayer, this class simply creates a connection to my database ``` //php class for connecting to database /** * Class DatabaseLayer - connects to database via PDO */ class DatabaseLayer { public $dbh; // handle of the db connexion /** * @param $config Config- configuration class */ private function __construct(Config $config) { $dsn = $config->read('db.dsn'); $user = $config->read('db.user'); $password = $config->read('db.password'); $this->dbh = new \PDO($dsn, $user, $password); } public function getConnection() { if ($this->dbh) { return $this->dbh; } return false; } } ``` Q1: i have `private function __construct(Config $config)` I'm not sure i fully understand the reason of having `__construct(Config $config)` instead of just using `__construct($config)` Does (`Config $config`) automatically create `$config` as a new `Config` instance? or do i have to do the following: ``` $config = new Config(); $dbLayer = new DatabaseLayer($config); ``` I want to extend the `DatabaseLayer` class and include methods for interacting with the database relating to my `GameUser` which is another class i have created, when i extend the `DatabaseLayer` class i need to inject the `GameUser` class I know my new class `DatabaseLayerUser` inherits the methods and properties from the `DatabaseLayer` class. Q2: as the new `DatabaseLayerUser` class is based on the 'DatabaseLayer' class it needs to have the `Config` class, because i used `__construct(Config $config)` does this get it automatically? or do i have to pass both the `Config` and `GameUser` to `DatabaseLayerUser` ``` class DatabaseLayerUser EXTENDS DatabaseLayer { private $config; /** @var Config */ private $user; /** @var GameUser */ /** * @param Config $config * @param GameUser $user */ private function __construct(Config $config, GameUser $user){ $this->config = $config; $this->user = $user; } /** * profileExists - Checks to see if a user profile exists * internal @var $PDOQuery * @var $PDOStatement PDOStatement * @throws Exception - details of PDOException * @return bool */ private function profileExists() { try{ $PDOQuery = ('SELECT count(1) FROM userprofile_upl WHERE uid_upl = :uid'); $PDOStatement = $this->dbh->prepare($PDOQuery); $PDOStatement->bindParam(':uid', $this->_userData->uid); $PDOStatement->execute(); return $PDOStatement->fetchColumn() >0; }catch(PDOException $e){ throw new Exception('Failed to check if profile exists for '.$this->_userData->uid, 0, $e); } } }` ``` Q3: i saw there is a `parent::__construct();` does this mean i should use: ``` private function __construct(Config $config, GameUser $user){ parent::__construct($config); $this->user = $user; } ```

Original source