I'm trying to implement best practices while learning PHP OOP. I understand the concept, but kind of doubt with proper implementation. As I'm trying to figure out the basic implementation principle, I'm not implementing DI container in this piece of code.
Db class for database connection.
Settings class, retrieve settings from db.
Languages class, retrieving information for a specific language.
Page class, Product class, Customer class, and many more.
Settings class needs Db class to retrieve settings.
Languages class needs both Db and Settings to retreive information based on settings from a database.
Page class needs Db, Settings and Languages. It may also need some other classes in the future.
Db.php extends PDO
Settings.php
class Settings
{
/* Database instance */
protected $db;
/* Cached settings */
private $settings = array();
public function __construct(Db $db)
{
$this->db = $db;
}
public function load ()
{
$selq = $this->db->query('SELECT setting, value FROM settings');
$this->settings = $selq->fetchAll();
}
}
Languages.php
class Languages
{
public $language;
protected $db;
protected $settings;
private $languages = array();
public function __construct(Db $db, Settings $settings)
{
$this->db = $db;
$this->settings = $settings;
// set value for $this->language based on user choice or default settings
...
}
public function load()
{
$this->languages = array();
$selq = $this->db->query('SELECT * FROM languages');
$this->languages = $selq->fetchAll();
}
}
Page.php
class Page
{
protected $db;
protected $settings;
protected $language;
public function __construct(Db $db, Settings $settings, Languages $languages)
{
$this->db = $db;
$this->settings = $settings;
$this->languages = $languages;
}
public function load()
{
// load page info from db with certain settings and in proper language
...
}
}
Config.php
$db = new Db;
/* Load all settings */
$settings = new Settings($db);
$settings->load();
/* Load all languages */
$languages = new Languages($db, $settings);
$languages->load();
/* Instantiate page */
$page = new Page($db, $settings, $languages);
I don't like the idea of injection same classes over and over again. This way, I'll get to the point, where I'll need to inject 10 classes. So, my code is wrong from the beginning.
Maybe, a better way is to do the following:
Config.php
$db = new Db;
/* Load all settings */
$settings = new Settings($db);
$settings->load();
/* Load all languages */
$languages = new Languages($settings);
$languages->load();
/* Instantiate page */
$page = new Page($languages);
as Settings already have access to $db, and $languages to both $db and $settings. However in this manner, I'll have to make calls like $this->languages->settings->db->...
All my code architecture seems to be completely wrong :) How it should be done?
I'll try to answer my own question, as I see it after studying lots and lots of materials.
1. Best practice is to create objects like:
$db = new Db();
$settings = new Settings ($db);
$languages = new Languages ($db, $settings);
// ...
2. Use DI container.
If you can't write one, use existing one. There are some, which call themselves DI containers not being them, like Pimple (there are several post about that on this site). Some tend to be much slower and much more complicated (Zend, Symfony), then the others, but also provide greater functionality. If you are reading this, then you should probably choose more simple one, like Aura, Auryn, Dice, PHP-DI (in alphabetical order). It's also important to know, that proper DI containers (as I see it) should have the ability to recursively traverse dependencies, meaning find dependencies needed for a certain object. They should also provide an ability to share same object (like $db instance).
3. Injecting dependencies manually will cause you lots of problems when trying to create objects dynamically (in case you use front controller and routing). That's why see point 2.
See great example here:
https://github.com/rdlowrey/Auryn#user-content-recursive-dependency-instantiation
https://github.com/rdlowrey/Auryn#instance-sharing
Video to watch:
https://www.youtube.com/watch?v=RlfLCWKxHJ0 (it's not PHP, but try to get the idea)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With