I've done quite a bit of reading on this and a lot of people are saying I should be using a singleton class. I was thinking of writing a "Config" class which would include a "config.php" file on __construct and loop through the $config array values and place them into $this->values...
But then I read more and more about how singletons should never be used. So my question is - what is the best approach for this? I want to have a configuration file, for organization purposes, that contains all of my $config variables. I do not want to be hardcoding things such as database usernames and passwords directly into methods, for the purpose of flexibility and whatnot.
For example, I use the following code in an MVC project I am working on:
public/index.php
<?php
include '../app/bootstrap.php';
?>
app/bootstrap.php
<?php
session_start();
function __autoload ($class) {
$file = '../app/'.str_replace('_', '/', strtolower($class)).'.php';
if (file_exists($file)) {
include $file;
}
else {
die($file.' not found');
}
}
$router = new lib_router();
?>
app/lib/router.php
<?php
class lib_router {
private $controller = 'controller_home'; // default controller
private $method = 'index'; // default method
private $params = array();
public function __construct () {
$this->getUrl()->route();
}
private function getUrl () {
if (isset($_GET['url'])) {
$url = trim($_GET['url'], '/');
$url = filter_var($url, FILTER_SANITIZE_URL);
$url = explode('/', $url);
$this->controller = isset($url[0]) ? 'controller_'.ucwords($url[0]) : $this->controller;
$this->method = isset($url[1]) ? $url[1] : $this->method;
unset($url[0], $url[1]);
$this->params = array_values($url);
}
return $this;
}
public function route () {
if (class_exists($this->controller)) {
if (method_exists($this->controller, $this->method)) {
call_user_func(array(new $this->controller, $this->method), $this->params);
}
else {
die('Method '.$this->method.' does not exist');
}
}
else {
die('Class '.$this->controller.' does not exist');
}
}
}
?>
Now let's say I visit http://localhost/myproject/lead/test
It is going to call the controller_lead class and the test method within.
Here is the code for app/controller/lead
<?php
class controller_lead extends controller_base {
public function test ($params) {
echo "lead test works!";
}
}
?>
app/controller/base
<?php
class controller_base {
private $db;
private $model;
public function __construct () {
$this->connect()->getModel();
}
private function connect () {
//$this->db = new PDO($config['db_type'] . ':host=' . $config['db_host'] . ';dbname=' . $config['db_name']. ', $config['db_user'], $config['db_pass'], $options);
return $this;
}
private function getModel () {
$model = str_replace('controller', 'model', get_class($this));
$this->model = new $model($this->db);
}
}
?>
This is where I run into the issue. As you can see, the connect method is going to try and create a new PDO object. Now how am I going to inject this $config variable, given all the other code I just provided?
My options appear to be:
- Use a singleton (bad)
- Use a global (worse)
- Include config.php in bootstrap.php, and inject it throughout multiple classes (Why should I inject this into my lib_router class when lib_router has absolutely nothing to do with the database? This sounds like terrible practice.)
What other option do I have? I don't want to do any of those 3 things...
Any help would be greatly appreciated.