Where and how to instantiate dependencies












1















I'm trying really hard to understand Dependency Injection and how to avoid globals, within the scope of the backend of a website project. Here I'm using PHP.



// MySQLDatabase.php
class MySQLDatabase
{
private $database;

public function __construct($db_host, $db_username, $db_password, $db_name) {
$this->database = new mysqli(
$db_host,
$db_username,
$db_password,
$db_name
);
}
}

// User.php
class User {
public function __construct($database, $id);
}

// Image.php
class Image {
public function __construct($database, $id);
}

$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);
$existingUser = new User($database, $userID);
$existingImage = new Image($database, $imageID);


I understand that in order to keep the code testable, contained, and without globals, I need to inject dependencies. Where I'm confused is where to instantiate these dependencies. Seems like every question about dependency injection is answered with the above code, and they say "That's how you do it!" But they never explain how to set up the rest of your program so that dependencies can be hooked together.



I first thought of using a bootstrap file which instantiates the dependencies first for the rest of the program to use:



// bootstrap.php
$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);


But this to me seems like I'm just creating a global here. Almost every one of my pages would need the database, and this database here would get passed around every script... Seems like a singleton to me (which everyone also says to avoid).



I could instantiate the database anywhere that I need it, on a page to page basis. This would mean the user.php page wouldn't use a bootstrap file, and just pull the dependencies it needs (database, user classes, etc). And this would happen on every page (user_images.php, login.php). But this seems like code repetition, because every page would have some of the same code. I've also thought about making a static-type class that makes it easier to instantiate the database, which you can load through a file:



// MySQLDatabase.php
class SpecificDatabase
{
private static $initialized = false;

public static function initialize($db_host, $db_username, $db_password, $db_name) {
if(self::$initialized) return;
self::$database = new MySQLDatabase(
$db_host,
$db_username,
$db_password,
$db_name
);
self::$initialized = true;
}
}


But in this case you would always have to get the db credentials to initialize the database every time you wanted to use it (unless you hard-coded it here, but I think that's just as bad). So littered throughout my code on almost every page would be the following:



require_once(__DIR__.'/vendor/autoload.php');
require_once(__DIR__.'/utilities/database/SpecificDatabase.php');
require_once(__DIR__.'/entities/User.php');

// load environment variables
$dotenv = new DotenvDotenv(__DIR__);
$dotenv->load();

$database = new SpecificDatabase(getenv('DATABASE_HOST'), getenv('DATABASE_USERNAME'), getenv('DATABASE_PASSWORD'), getenv('DATABASE_NAME'));
$user = new User($database, $userID);


Could someone help me understand this better? I really want to be a great programmer. There are just some hurdles that are taking me a lot longer to understand, and I think it might come down to some simple misunderstandings, especially vocabulary - for example, I think I am blocked by the paradox of avoiding repetition AND avoiding globals. Most of my study of dependency injection comes to the conclusion of pulling dependencies out from inside classes. But when they get pulled out, where do they go...?










share|improve this question























  • Look into something like dependency injection containers, which remove certain problems of dealing with DI. In general, yes, you need to instantiate your dependencies and objects like this. When it becomes too much of a problem, you can create factory objects/functions to move that code out of the way a bit. The main point is that you keep the instantiation out of your objects and only instantiate the specific objects in your specific context; i.e. you would use different such factories in production and in your unit tests.

    – deceze
    Nov 22 '18 at 15:56











  • @deceze Yes, I have looked a little into DI Containers. I haven't actually used one yet. Is it similar to how my static class worked above? Doesn't a DI Container simply move the dependencies out of your classes and into hidden classes?

    – claust
    Nov 22 '18 at 16:55











  • Sort of. You tell a DI Container the relationships between your classes (what depends on what), and then you just ask it to give you an instance of a specific class and it’ll sort out all the required dependencies and their dependencies. It simplifies the potentially complex dependency tree to a configuration issue.

    – deceze
    Nov 22 '18 at 17:02
















1















I'm trying really hard to understand Dependency Injection and how to avoid globals, within the scope of the backend of a website project. Here I'm using PHP.



// MySQLDatabase.php
class MySQLDatabase
{
private $database;

public function __construct($db_host, $db_username, $db_password, $db_name) {
$this->database = new mysqli(
$db_host,
$db_username,
$db_password,
$db_name
);
}
}

// User.php
class User {
public function __construct($database, $id);
}

// Image.php
class Image {
public function __construct($database, $id);
}

$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);
$existingUser = new User($database, $userID);
$existingImage = new Image($database, $imageID);


I understand that in order to keep the code testable, contained, and without globals, I need to inject dependencies. Where I'm confused is where to instantiate these dependencies. Seems like every question about dependency injection is answered with the above code, and they say "That's how you do it!" But they never explain how to set up the rest of your program so that dependencies can be hooked together.



I first thought of using a bootstrap file which instantiates the dependencies first for the rest of the program to use:



// bootstrap.php
$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);


But this to me seems like I'm just creating a global here. Almost every one of my pages would need the database, and this database here would get passed around every script... Seems like a singleton to me (which everyone also says to avoid).



I could instantiate the database anywhere that I need it, on a page to page basis. This would mean the user.php page wouldn't use a bootstrap file, and just pull the dependencies it needs (database, user classes, etc). And this would happen on every page (user_images.php, login.php). But this seems like code repetition, because every page would have some of the same code. I've also thought about making a static-type class that makes it easier to instantiate the database, which you can load through a file:



// MySQLDatabase.php
class SpecificDatabase
{
private static $initialized = false;

public static function initialize($db_host, $db_username, $db_password, $db_name) {
if(self::$initialized) return;
self::$database = new MySQLDatabase(
$db_host,
$db_username,
$db_password,
$db_name
);
self::$initialized = true;
}
}


But in this case you would always have to get the db credentials to initialize the database every time you wanted to use it (unless you hard-coded it here, but I think that's just as bad). So littered throughout my code on almost every page would be the following:



require_once(__DIR__.'/vendor/autoload.php');
require_once(__DIR__.'/utilities/database/SpecificDatabase.php');
require_once(__DIR__.'/entities/User.php');

// load environment variables
$dotenv = new DotenvDotenv(__DIR__);
$dotenv->load();

$database = new SpecificDatabase(getenv('DATABASE_HOST'), getenv('DATABASE_USERNAME'), getenv('DATABASE_PASSWORD'), getenv('DATABASE_NAME'));
$user = new User($database, $userID);


Could someone help me understand this better? I really want to be a great programmer. There are just some hurdles that are taking me a lot longer to understand, and I think it might come down to some simple misunderstandings, especially vocabulary - for example, I think I am blocked by the paradox of avoiding repetition AND avoiding globals. Most of my study of dependency injection comes to the conclusion of pulling dependencies out from inside classes. But when they get pulled out, where do they go...?










share|improve this question























  • Look into something like dependency injection containers, which remove certain problems of dealing with DI. In general, yes, you need to instantiate your dependencies and objects like this. When it becomes too much of a problem, you can create factory objects/functions to move that code out of the way a bit. The main point is that you keep the instantiation out of your objects and only instantiate the specific objects in your specific context; i.e. you would use different such factories in production and in your unit tests.

    – deceze
    Nov 22 '18 at 15:56











  • @deceze Yes, I have looked a little into DI Containers. I haven't actually used one yet. Is it similar to how my static class worked above? Doesn't a DI Container simply move the dependencies out of your classes and into hidden classes?

    – claust
    Nov 22 '18 at 16:55











  • Sort of. You tell a DI Container the relationships between your classes (what depends on what), and then you just ask it to give you an instance of a specific class and it’ll sort out all the required dependencies and their dependencies. It simplifies the potentially complex dependency tree to a configuration issue.

    – deceze
    Nov 22 '18 at 17:02














1












1








1


1






I'm trying really hard to understand Dependency Injection and how to avoid globals, within the scope of the backend of a website project. Here I'm using PHP.



// MySQLDatabase.php
class MySQLDatabase
{
private $database;

public function __construct($db_host, $db_username, $db_password, $db_name) {
$this->database = new mysqli(
$db_host,
$db_username,
$db_password,
$db_name
);
}
}

// User.php
class User {
public function __construct($database, $id);
}

// Image.php
class Image {
public function __construct($database, $id);
}

$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);
$existingUser = new User($database, $userID);
$existingImage = new Image($database, $imageID);


I understand that in order to keep the code testable, contained, and without globals, I need to inject dependencies. Where I'm confused is where to instantiate these dependencies. Seems like every question about dependency injection is answered with the above code, and they say "That's how you do it!" But they never explain how to set up the rest of your program so that dependencies can be hooked together.



I first thought of using a bootstrap file which instantiates the dependencies first for the rest of the program to use:



// bootstrap.php
$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);


But this to me seems like I'm just creating a global here. Almost every one of my pages would need the database, and this database here would get passed around every script... Seems like a singleton to me (which everyone also says to avoid).



I could instantiate the database anywhere that I need it, on a page to page basis. This would mean the user.php page wouldn't use a bootstrap file, and just pull the dependencies it needs (database, user classes, etc). And this would happen on every page (user_images.php, login.php). But this seems like code repetition, because every page would have some of the same code. I've also thought about making a static-type class that makes it easier to instantiate the database, which you can load through a file:



// MySQLDatabase.php
class SpecificDatabase
{
private static $initialized = false;

public static function initialize($db_host, $db_username, $db_password, $db_name) {
if(self::$initialized) return;
self::$database = new MySQLDatabase(
$db_host,
$db_username,
$db_password,
$db_name
);
self::$initialized = true;
}
}


But in this case you would always have to get the db credentials to initialize the database every time you wanted to use it (unless you hard-coded it here, but I think that's just as bad). So littered throughout my code on almost every page would be the following:



require_once(__DIR__.'/vendor/autoload.php');
require_once(__DIR__.'/utilities/database/SpecificDatabase.php');
require_once(__DIR__.'/entities/User.php');

// load environment variables
$dotenv = new DotenvDotenv(__DIR__);
$dotenv->load();

$database = new SpecificDatabase(getenv('DATABASE_HOST'), getenv('DATABASE_USERNAME'), getenv('DATABASE_PASSWORD'), getenv('DATABASE_NAME'));
$user = new User($database, $userID);


Could someone help me understand this better? I really want to be a great programmer. There are just some hurdles that are taking me a lot longer to understand, and I think it might come down to some simple misunderstandings, especially vocabulary - for example, I think I am blocked by the paradox of avoiding repetition AND avoiding globals. Most of my study of dependency injection comes to the conclusion of pulling dependencies out from inside classes. But when they get pulled out, where do they go...?










share|improve this question














I'm trying really hard to understand Dependency Injection and how to avoid globals, within the scope of the backend of a website project. Here I'm using PHP.



// MySQLDatabase.php
class MySQLDatabase
{
private $database;

public function __construct($db_host, $db_username, $db_password, $db_name) {
$this->database = new mysqli(
$db_host,
$db_username,
$db_password,
$db_name
);
}
}

// User.php
class User {
public function __construct($database, $id);
}

// Image.php
class Image {
public function __construct($database, $id);
}

$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);
$existingUser = new User($database, $userID);
$existingImage = new Image($database, $imageID);


I understand that in order to keep the code testable, contained, and without globals, I need to inject dependencies. Where I'm confused is where to instantiate these dependencies. Seems like every question about dependency injection is answered with the above code, and they say "That's how you do it!" But they never explain how to set up the rest of your program so that dependencies can be hooked together.



I first thought of using a bootstrap file which instantiates the dependencies first for the rest of the program to use:



// bootstrap.php
$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);


But this to me seems like I'm just creating a global here. Almost every one of my pages would need the database, and this database here would get passed around every script... Seems like a singleton to me (which everyone also says to avoid).



I could instantiate the database anywhere that I need it, on a page to page basis. This would mean the user.php page wouldn't use a bootstrap file, and just pull the dependencies it needs (database, user classes, etc). And this would happen on every page (user_images.php, login.php). But this seems like code repetition, because every page would have some of the same code. I've also thought about making a static-type class that makes it easier to instantiate the database, which you can load through a file:



// MySQLDatabase.php
class SpecificDatabase
{
private static $initialized = false;

public static function initialize($db_host, $db_username, $db_password, $db_name) {
if(self::$initialized) return;
self::$database = new MySQLDatabase(
$db_host,
$db_username,
$db_password,
$db_name
);
self::$initialized = true;
}
}


But in this case you would always have to get the db credentials to initialize the database every time you wanted to use it (unless you hard-coded it here, but I think that's just as bad). So littered throughout my code on almost every page would be the following:



require_once(__DIR__.'/vendor/autoload.php');
require_once(__DIR__.'/utilities/database/SpecificDatabase.php');
require_once(__DIR__.'/entities/User.php');

// load environment variables
$dotenv = new DotenvDotenv(__DIR__);
$dotenv->load();

$database = new SpecificDatabase(getenv('DATABASE_HOST'), getenv('DATABASE_USERNAME'), getenv('DATABASE_PASSWORD'), getenv('DATABASE_NAME'));
$user = new User($database, $userID);


Could someone help me understand this better? I really want to be a great programmer. There are just some hurdles that are taking me a lot longer to understand, and I think it might come down to some simple misunderstandings, especially vocabulary - for example, I think I am blocked by the paradox of avoiding repetition AND avoiding globals. Most of my study of dependency injection comes to the conclusion of pulling dependencies out from inside classes. But when they get pulled out, where do they go...?







php dependency-injection






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 22 '18 at 13:25









claustclaust

657




657













  • Look into something like dependency injection containers, which remove certain problems of dealing with DI. In general, yes, you need to instantiate your dependencies and objects like this. When it becomes too much of a problem, you can create factory objects/functions to move that code out of the way a bit. The main point is that you keep the instantiation out of your objects and only instantiate the specific objects in your specific context; i.e. you would use different such factories in production and in your unit tests.

    – deceze
    Nov 22 '18 at 15:56











  • @deceze Yes, I have looked a little into DI Containers. I haven't actually used one yet. Is it similar to how my static class worked above? Doesn't a DI Container simply move the dependencies out of your classes and into hidden classes?

    – claust
    Nov 22 '18 at 16:55











  • Sort of. You tell a DI Container the relationships between your classes (what depends on what), and then you just ask it to give you an instance of a specific class and it’ll sort out all the required dependencies and their dependencies. It simplifies the potentially complex dependency tree to a configuration issue.

    – deceze
    Nov 22 '18 at 17:02



















  • Look into something like dependency injection containers, which remove certain problems of dealing with DI. In general, yes, you need to instantiate your dependencies and objects like this. When it becomes too much of a problem, you can create factory objects/functions to move that code out of the way a bit. The main point is that you keep the instantiation out of your objects and only instantiate the specific objects in your specific context; i.e. you would use different such factories in production and in your unit tests.

    – deceze
    Nov 22 '18 at 15:56











  • @deceze Yes, I have looked a little into DI Containers. I haven't actually used one yet. Is it similar to how my static class worked above? Doesn't a DI Container simply move the dependencies out of your classes and into hidden classes?

    – claust
    Nov 22 '18 at 16:55











  • Sort of. You tell a DI Container the relationships between your classes (what depends on what), and then you just ask it to give you an instance of a specific class and it’ll sort out all the required dependencies and their dependencies. It simplifies the potentially complex dependency tree to a configuration issue.

    – deceze
    Nov 22 '18 at 17:02

















Look into something like dependency injection containers, which remove certain problems of dealing with DI. In general, yes, you need to instantiate your dependencies and objects like this. When it becomes too much of a problem, you can create factory objects/functions to move that code out of the way a bit. The main point is that you keep the instantiation out of your objects and only instantiate the specific objects in your specific context; i.e. you would use different such factories in production and in your unit tests.

– deceze
Nov 22 '18 at 15:56





Look into something like dependency injection containers, which remove certain problems of dealing with DI. In general, yes, you need to instantiate your dependencies and objects like this. When it becomes too much of a problem, you can create factory objects/functions to move that code out of the way a bit. The main point is that you keep the instantiation out of your objects and only instantiate the specific objects in your specific context; i.e. you would use different such factories in production and in your unit tests.

– deceze
Nov 22 '18 at 15:56













@deceze Yes, I have looked a little into DI Containers. I haven't actually used one yet. Is it similar to how my static class worked above? Doesn't a DI Container simply move the dependencies out of your classes and into hidden classes?

– claust
Nov 22 '18 at 16:55





@deceze Yes, I have looked a little into DI Containers. I haven't actually used one yet. Is it similar to how my static class worked above? Doesn't a DI Container simply move the dependencies out of your classes and into hidden classes?

– claust
Nov 22 '18 at 16:55













Sort of. You tell a DI Container the relationships between your classes (what depends on what), and then you just ask it to give you an instance of a specific class and it’ll sort out all the required dependencies and their dependencies. It simplifies the potentially complex dependency tree to a configuration issue.

– deceze
Nov 22 '18 at 17:02





Sort of. You tell a DI Container the relationships between your classes (what depends on what), and then you just ask it to give you an instance of a specific class and it’ll sort out all the required dependencies and their dependencies. It simplifies the potentially complex dependency tree to a configuration issue.

– deceze
Nov 22 '18 at 17:02












0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53432009%2fwhere-and-how-to-instantiate-dependencies%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53432009%2fwhere-and-how-to-instantiate-dependencies%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Create new schema in PostgreSQL using DBeaver

Deepest pit of an array with Javascript: test on Codility

Costa Masnaga