Where and how to instantiate dependencies
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
add a comment |
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
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
add a comment |
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
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
php dependency-injection
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
add a comment |
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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