First, it turns out that the "standards are not mandatory", in other words, they are not the rule for anything, they are a solution to common problems encountered during the development of a project. They are like tools that we should use only when necessary, not when we think necessary or even because we think we should use them.
Injecting a connection into a class is the same as injecting a connection instance into a class. And according to Wikipédia ...
Dependency injection (Dependency Injection) is a standard of computer program development used when it is necessary to maintain a low level of coupling between different modules of a system. In this solution the dependencies between modules are not defined programmatically, but rather by the configuration of a software infrastructure (container) that is responsible for "injecting" into each component its declared dependencies. Dependency injection is related to the pattern Inversion of control but cannot be considered a synonym of this. It is also directly associated with Ioc as mentioned above and Strategy Patterns. «1»
A dependency can be seen as a consumable service, and an injection as a consumed service.
Example: To use the services of a particular operator, we put a chip of the same operator on the mobile phone and this phone provides the network and the services, and we consume these services whatever they are, depending on the chip used. In that case we would have the mobile phone as container, responsible for introducing these services to the user.
Like any other design pattern, these do not escape logic, if used when unnecessary becomes a nuisance, the code becomes too complex at the expense of nothing and who knows what other problems may cause. And from what I see is clearly what will happen to you. By choosing to extend the class PDO instead of initiating an instance in a constructor as is common, it is clear that you wanted something simple, and a CMS is basically an application aimed at CRUD and other basic operations. I think if you use a normal connection class there won’t be any complication.
It is one thing to want to learn and another to use unnecessarily. As far as I’m concerned, if you want to learn how to work with Patterns, I recommend looking for something more focused on Patterns to work with, rather than investing unnecessary resources in something you can do at no cost, if you know what I mean.
When it’s convenient ?
- You need to inject configuration data into one or more components.
- You need to inject the same dependency into multiple components.
- You need to inject different implementations of the same dependency.
- You need to inject the same implementation into different configurations.
- You need some of the services provided by the container.
Without further ado, I think it’s time to move on to some examples of use, but if you want to dig deeper into injections, and also know what disadvantages they have, or even points for me omitted, recommend you read these articles:
Or you could just use the Google for more results. Also, if you find it unclear, analyze the code of a framework anyone who has any of these standards implemented, so you can see how they are applied in production.
Example without an injection:
<?php
#classe de conexão que estende a classe PDO
class Database extends PDO
{
private $data;
public function __construct()
{
# @Configuracao
$dsn = 'mysql:host=localhost;dbname=exemplo;charset=utf8;';
$param = array('dsn'=>$dsn, 'user'=>'root', 'pwd'=>'');
if(!empty($param)){
try{
parent::__construct($param['dsn'], $param['user'], $param['pwd']);
} catch(PDOException $e){
die($e->getMessage());
}
}
}
public function select($tabela, $args=null){
if(!empty($tabela)){
if(!empty($args)){
$sql = "SELECT * FROM {$tabela} WHERE {$args[0]} {$args[1]} {$args[1]}";
} else {
$sql = "SELECT * FROM {$tabela}";
}
if($this->data = parent::query($sql)){
return $this->data;
}
}
return false;
}
}
?>
Class of consumer of connection
<?php
require_once 'class.database.php';
class Books
{
private $_db;
public function __construct()
{
$this->_db = new Database();
}
public function fetchAll($tabela)
{
if($query = $this->_db->select($tabela)){
if($resultado = $query->fetchAll(PDO::FETCH_OBJ));
return $resultado;
}
return false;
}
}
$instancia = new Books();
$livros = $instancia->fetchAll('exemplo');
foreach($livros as $livro){
print "ID: #" . $livro->id . "<br/>";
print "Titulo: " . $livro->titulo . "<br/>";
}
?>
Example with injection:
<?php
include_once 'class.container.php';
class Books
{
private $_db;
// Construtor
public function __construct(Container $param)
{
$this->_db = $param->Connect();
}
// Método que faz uso dessa instancia
public function getAll($tabela)
{
$sql = "SELECT * FROM {$tabela}";
if($query = $this->_db->query($sql)){
while($resultado = $query->fetchAll(PDO::FETCH_OBJ)){
return $resultado;
}
}
return false;
}
}
# @Books exemplo
# @Configuração:
$param = array('dsn'=>'mysql:host=localhost;dbname=exemplo;charset=utf8;',
'user'=>'root',
'pwd'=>'');
# Injecção do @Container na classe @Books
$livros = new Books(new Container($param));
# Retornar os resultados da tabela @exemplo
$resultados = $livros->getAll('exemplo');
foreach($resultados as $resultado){
print $resultado->titulo . "<br/>";
}
?>
This would be the container, using a builder.
<?php
class Container
{
private $instancia, $params;
public function __construct($params)
{
$this->params = $params;
}
public function Connect()
{
if(empty($this->instancia['db']))
{
$this->instancia['db'] = new PDO($this->params['dsn'],
$this->params['user'],
$this->params['pwd']
);
}
return $this->instancia['db'];
}
}
?>
These past examples, are very simple implementations of this pattern, usually create more complex routes to work more deliberately with different configurations in various situations. These configurations that are there, are something that is almost not seen in a deeper implementation of the standard.
In the end, I don’t know if I’ve made one or a few mistakes somewhere, but this is it, the most comprehensive answer I’ve been able to give.
No matter how many questions you ask, and with each answer you receive, you won’t be able to understand exactly where and when they should be used, so I recommend that you try before, and only then question. This is because, even if someone explains it to you and gives you an example now, it is very likely that you will continue unanswered, this because this type of pattern is both unique and common depending on the situation.
– Edilson
My fear is just to wear it and regret it later..
– Renan Cavalieri
"but I’m doing it as a form of study" - This is the best time for testing, what works and how it works and what the drawbacks of using this standard in this app. And using the DI, you’d have to rewrite a sizeable portion of your script.
– Edilson
The code itself is quite small, I’m trying to do with low coupling, so I guess I won’t have so much work. But seeing as how Singleton doesn’t work the way I’d hoped, I kind of abandoned him. I don’t want my views to have access to my database, you know? In this case I prefer something more encapsulated.
– Renan Cavalieri
"But seeing as how Singleton doesn’t work the way I’d hoped" - It’s not to work the way you expect it to, it’s going to work the way it works, that’s what patterns do, they’re used to solve specific, very specific problems that the programmer encounters during the construction of the project. They are a kind of compact logic, not exactly applicable in any situation. Talks of "permanent connection", and referes CMS, but you cite a pattern that has other responsibilities. This is basically what I’m talking about.
– Edilson