Where and how to instantiate dependencies - php

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 Dotenv\Dotenv(__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...?

Related

How to avoid a construct being called twice

Currently trying to learn the "right" way to build a site with OOP and the MVC model, and obviously running into some stumbling blocks since I've been doing mostly procedural for years.
(I'm also using PHP 7 for the first time since I've been stuck with PHP 5 for years and years, so also trying to code the "right" way using mysqli_ instead of the old mysql_. Learning prepared statements for the first time also instead of just escaping all my variables, but that's a whole different discussion)
Right now I have a few different classes:
config.class.php -> Config -> set up the db connection and other site settings
leads.class.php -> Leads extends Config -> get lead info from the db upon request (when someone hits the site)
questions.class.php -> Questions extends Config -> get question info (it's a survey site)
leadsview.class.php -> -> LeadsView extends Leads -> display lead info if needs be
questionsview.class.php -> QuestionsView extends Questions -> display question info on the page after it's pulled from the db
So, let's say on my index.php I need to instantiate both QuestionsView and LeadsView so I can display questions and lead info on the page, respectively. So I do this:
session_start();
include_once 'lib/autoload.php'; // class autoloader
$l = new LeadsView();
$q = new QuestionsView();
Totally works fine so far. BUT - in my Config class I not only have a database connection, but a few site configuration settings inside a constructor that need to be set when someone first hits the page. Something like this so far:
class Config {
// set up db connection
private $db_host;
private $db_user;
private $db_password;
private $db_name;
protected $conn;
protected $flow_id;
protected $domain;
public function __construct() {
$this->flow_id = $_REQUEST['flow'];
$this->domain = $_SERVER['HTTP_HOST'];
$this->connect(); // open the db connection
print "hey<br>";
}
protected function connect($db = "default") {
switch ($db) {
// allow for different db connections in the future
case "default":
$this->db_host = "XXXX";
$this->db_user = "XXXX";
$this->db_password = "XXXX";
$this->db_name = "XXXX";
break;
}
$this->conn = new mysqli($this->db_host, $this->db_user, $this->db_password, $this->db_name);
$this->conn->set_charset("utf8mb4");
if ($this->conn->connect_error) {
die("Error connecting to db: " . $this->conn->connect_error);
}
}
}
I threw in that print "hey<br>"; just to make sure that constructor was being run. But now it's being run twice: once from my $l = new LeadsView(); and once from $q = new QuestionsView(); since they both extend Config. I don't need or want to run that constructor twice, for obvious reasons.
So my question is: what's the proper way to set up a configuration class in a scenario like this? Should I create a Dbh class separate from Config, and just have all my questions, leads, etc. classes extend Dbh instead so they don't all run the Config methods as well? Is there some other obvious way to do this that I'm completely missing?
Your classes should never extend from Config or Database class or anything like that. This is not how polymorphism works.
In fact, your Config class isn't very useful. To make use of such class you need methods that actually help you perform prepared statements. The connect() method is not needed and you definitely do not need all the properties.
If we were going to fix this class then we could do something like this:
class Database {
protected $conn;
protected $flow_id;
protected $domain;
public function __construct(string $db) {
$this->flow_id = $_REQUEST['flow'];
$this->domain = $_SERVER['HTTP_HOST'];
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
// Load the variable from the config file
$this->conn = new mysqli($db_host, $db_user, $db_password, $db_name);
$this->conn->set_charset("utf8mb4");
}
//
// The rest of your database abstraction methods. Some methods that help you write parameterized queries more easily
// Without other methods this class would be useless!
}
The name of the class doesn't make sense. It is not a config class. It is an abstraction around mysqli. The config details should be stored in a separate file.
When you need to use this class in another class, simply require it as a parameter.
$db = new Database();
$l = new LeadsView($db);
This is called dependency injection. You should use this pattern in your code when working with OOP as it will make a lot of interactions between your classes much simpler. You can also implement IoC container. Nette has a good tutorial, but you can also use their implementation.
I would strongly recommend to don't reinvent the wheel. There are already good libraries that provide abstraction around PDO. Yes, PDO not mysqli. Do not waste your time with mysqli unless you have an extremely good reason to use mysqli. Use PDO with an abstraction library such as EasyDB
You are using inheritance. You probably want to use composition instead. Concretely this means providing the Config to LeadsView or Questionsview.
$config = new Config();
$leadsview = new LeadsView( $config );
class Config {
__construct() {
// do whatever
}
}
class LeadsView {
private $config;
__construct( $config ) {
$this->config = $config;
}
// use this->config somewhere in Leadsview to get whatever you need
}
To prevent the usage of multiple instances of Config you can use a single reference (this requires your discipline to enforce).
Otherwise you can create config as a singleton, which guarantees only one version of Config exists. If you want to know more about Singletons you can look it up, it's a very well know pattern.

Initialize php class with same name

If we have two or more classes with the same name, but in different folders, how would one differentiate between them during initialization?
require_once('database.php');
require_once('t/database.php');
$db = new Database(); // I want this to initialize the one in t/database.php
$globalDb = new Database(); // I want this to initialize database.php
This is what Namespaces are for.
But honestly, this sounds like an architectural problem. There are two ways you can approach this. If we were to answer your question as posed, you could solve your problem like so:
database.php
class Database{
// ...
}
t/database.php
namespace T;
class Database{
// ...
}
index.php
require_once('database.php');
require_once('t/database.php');
$db = new T\Database();
$globalDb = new Database();
But judging by your naming conventions, it appears as if you have two separate classes that are intended to interact with either the same - or similar - database instances.
I'm making some assumptions here, but the other way you can set up your logic is to condense your code down to a single Database class and operate on multiple connections over multiple instances.
Consider using dependency injection to manage your connections in a single unified class structure, especially if you're using the same type of RDBMS flavor across all connections.
Consider something like the following naive example:
class Database{
private $conn;
public function __construct(PDO $conn){
$this->conn = $conn;
}
public function select(...$args) { // Select Logic goes here }
public function insert(...$args) { // Insert Logic goes here }
public function update(...$args) { // Update Logic goes here }
public function delete(...$args) { // Delete Logic goes here }
}
It would be possible to operate over multiple connections at once by simply injecting different PDO instances into the same class:
require_once('database.php');
$conn1 = new PDO('mysql:host=localhost;dbname=test1', $user, $pass);
$conn2 = new PDO('mysql:host=localhost;dbname=test2', $user, $pass);
$db1 = new Database($conn1);
$db2 = new Database($conn2);
So while the first example may address your question directly, you may want to rethink your architecture if I'm on the right track with my second example.
And to echo everyone else, you should seriously consider using a proper Autoloader. Look into Composer and Autoloading - specifically PSR-4.
If we have two or more classes with the same name, but in different folders, how would one differentiate between them during initialization?
Don't do that. Loading the PHP file which contains the second definition will throw an error:
Fatal error: Cannot declare class Database, because the name is already in use
You will need to rename one of the classes.
As an aside, you may want to consider using an autoloader in your application instead of calling require() manually.

database parameters on function __construct

I am wondering if my understanding is right.
I placed my database connection parameter on my __construct(), so this means every time the class is instantiated, I also reconnect to my database, right?
private $handle;
public function __construct()
{
$username = "test";
$password = "9712nc*<?12";
$host = "localhost";
$db = "miner";
$dsn = 'mysql:dbname='.$db.';host='.$host;
try {
$this->handle = new PDO($dsn,$username,$password);
}
catch(PDOException $e) {
print $e->getMessage();
die();
}
}
Is this a good practice if I have many request from a certain user? Does this mean every time a user make a request (even if the request is just done minutes ago) the script should first connect to the database? Is there any appropriate way I can preserve my $handle?
BTW: The database connection is working fine.
If the class is instantiated once, then you're going to be just fine. In this case, you open one connection only.
If you instantiate the class several times, or use it as a static class, then you're potentially going to create a connection each time, which is not ideal.
If you keep the classes all active (i.e. you never delete reference to a class once you create it, from memory (I've never tested it) the internals of PHP should actually sort this out for you, and you'll still only have the one connection to the database. But if you lost a handle to the class you created, then the PDO will be destroyed and you start again. If you are using as a static class (i.e. you call it with class:function()), then you're on the wrong path.
There are two common solutions, and you'll find arguements for and against both of them.
1) Use a global for storing your DB connection. You create the $handle = PDO and store $handle as a global variable. Easy to pass around. Easy to overwrite - I'm not going to debate here.
2) Create a "static" class (commonly called a Singleton) that you recall. The basic structure would be
private static $ThisObj;
private static $handle;
public static function getInstance() {
if( !(self::$ThisObj instanceof SoapDB) ) {
self::$ThisObj = new SoapDB();
try {
$this->handle = new PDO_Handler('mysql:dbname=' . DB_NAME . ';host=' . DB_HOST, DB_USER, DB_PASS);
$this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
// Error Here
}
}
return self::$ThisObj;
}
Using this, you would normally create a separate DB class as a singleton. Using Singleton vs Global: your call (after research).
3) The third answer is if you are only ever calling your class above as a static (i.e. you call class::function()) then you can just make the $handle as a static and actually your problems should be wonderously solved. Essentially you're creating a Singleton, with the database as one of the properties.
Sorry that there's no wrong or right answer.
Edit based on comment "What's a static class":
Strictly speaking, I should say "class with static properties". To explain, normally you create a class with the syntax:
$myClass = new class();
$methodResult = $myClass->method();
and then do lots of nifty little things with $myClass by calling functions. You can then drop reference to the class, lose the properties (variables) and will reinitilaise later on.
A static class (for the purposes of this answer) is one where you have static properties. Normally (not absolutely) they are called by going.
$methodResult = class::method();
You don't hold on to the class - it gets initiated, used and dropped. However, if you store properties (vars) as static then each time you use that class, those properties will still exist in the state they last were. So method can set $this->MyVar = 'something' and next time, $this->MyVar will still be something.
Very useful for compartmentalising your code, stops functions overwriting others and can make unit testing easier.
(Note - I'm generalising to make it simpler. But it should give you an idea of the processes.)
You should use singleton.
try google 'mysql php singleton'
eg.
http://www.swhistlesoft.com/blog/2011/08/05/1435-mysql-singleton-class-to-allow-easy-and-clean-access-to-common-mysql-commands

How to properly set up a PDO connection

From time to time I see questions regarding connecting to database.
Most answers is not the way I do it, or I might just not get the answers correctly. Anyway; I've never thought about it because the way I do it works for me.
But here's a crazy thought; Maybe I'm doing this all wrong, and if that's the case; I would really like to know how to properly connect to a MySQL database using PHP and PDO and make it easy accessible.
Here's how I'm doing it:
First off, here's my file structure (stripped down):
public_html/
* index.php
* initialize/
-- load.initialize.php
-- configure.php
-- sessions.php
index.php
At the very top, I have require('initialize/load.initialize.php');.
load.initialize.php
# site configurations
require('configure.php');
# connect to database
require('root/somewhere/connect.php'); // this file is placed outside of public_html for better security.
# include classes
foreach (glob('assets/classes/*.class.php') as $class_filename){
include($class_filename);
}
# include functions
foreach (glob('assets/functions/*.func.php') as $func_filename){
include($func_filename);
}
# handle sessions
require('sessions.php');
I know there's a better, or more correct, way to include classes, but can't remember what it was. Haven't gotten the time to look into it yet, but I think it was something with autoload. something like that...
configure.php
Here I basically just override some php.ini-properties and do some other global configuration for the site
connect.php
I've put the connection onto a class so other classes can extends this one...
class connect_pdo
{
protected $dbh;
public function __construct()
{
try {
$db_host = ' '; // hostname
$db_name = ' '; // databasename
$db_user = ' '; // username
$user_pw = ' '; // password
$con = new PDO('mysql:host='.$db_host.'; dbname='.$db_name, $db_user, $user_pw);
$con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$con->exec("SET CHARACTER SET utf8"); // return all sql requests as UTF-8
}
catch (PDOException $err) {
echo "harmless error message if the connection fails";
$err->getMessage() . "<br/>";
file_put_contents('PDOErrors.txt',$err, FILE_APPEND); // write some details to an error-log outside public_html
die(); // terminate connection
}
}
public function dbh()
{
return $this->dbh;
}
}
# put database handler into a var for easier access
$con = new connect_pdo();
$con = $con->dbh();
//
Here I do believe there's room for massive improvement since I recently started learning OOP, and using PDO instead of mysql.
So I've just followed a couple of beginners tutorials and tried out different stuff...
sessions.php
Beside handling regular sessions, I also initialize some classes into a session like this:
if (!isset($_SESSION['sqlQuery'])){
session_start();
$_SESSION['sqlQuery'] = new sqlQuery();
}
This way this class is available all over the place. This might not be good practice(?)...
Anyway, this is what this approach allows me to do from everywhere:
echo $_SESSION['sqlQuery']->getAreaName('county',9); // outputs: Aust-Agder (the county name with that id in the database)
Inside my sqlQuery-class, which extends my connect_pdo-class, I have a public function called getAreaName which handles the request to my database.
Pretty neat I think.
Works like a charm
So that's basically how I'm doing it.
Also, whenever I need to fetch something from my DB from not within a class, I just do something similar to this:
$id = 123;
$sql = 'SELECT whatever FROM MyTable WHERE id = :id';
$qry = $con->prepare($sql);
$qry -> bindParam(':id', $id, PDO::PARAM_INT);
$qry -> execute();
$get = $qry->fetch(PDO::FETCH_ASSOC);
Since I put the connection into a variable inside connect_pdo.php, I just have referring to it and I'm good to go. It works. I get my expected results...
But regardless of that; I would really appreciate if you guys could tell me if I'm way off here. What I should do instead, areas I could or should change for improvement etc...
I'm eager to learn...
The goal
As I see it, your aim in this case is twofold:
create and maintain a single/reusable connection per database
make sure that the connection has been set up properly
Solution
I would recommend to use both anonymous function and factory pattern for dealing with PDO connection. The use of it would looks like this :
$provider = function()
{
$instance = new PDO('mysql:......;charset=utf8', 'username', 'password');
$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $instance;
};
$factory = new StructureFactory( $provider );
Then in a different file or lower in the same file:
$something = $factory->create('Something');
$foobar = $factory->create('Foobar');
The factory itself should look something like this:
class StructureFactory
{
protected $provider = null;
protected $connection = null;
public function __construct( callable $provider )
{
$this->provider = $provider;
}
public function create( $name)
{
if ( $this->connection === null )
{
$this->connection = call_user_func( $this->provider );
}
return new $name( $this->connection );
}
}
This way would let you have a centralized structure, which makes sure that connection is created only when required. It also would make the process of unit-testing and maintenance much easier.
The provider in this case would be found somewhere at the bootstrap stage. This approach would also give a clear location where to define the configuration, that you use for connecting to the DB.
Keep in mind that this is an extremely simplified example. You also might benefit from watching two following videos:
Global State and Singletons
Don't Look For Things!
Also, I would strongly recommend reading a proper tutorial about use of PDO (there are a log of bad tutorial online).
I would suggest not using $_SESSION to access your DB connection globally.
You can do one of a few things (in order of worst to best practices):
Access $dbh using global $dbh inside of your functions and classes
Use a singleton registry, and access that globally, like so:
$registry = MyRegistry::getInstance();
$dbh = $registry->getDbh();
Inject the database handler into the classes that need it, like so:
class MyClass {
public function __construct($dbh) { /* ... */ }
}
I would highly recommend the last one. It is known as dependency injection (DI), inversion of control (IoC), or simply the Hollywood principle (Don't call us, we'll call you).
However, it is a little more advanced and requires more "wiring" without a framework. So, if dependency injection is too complicated for you, use a singleton registry instead of a bunch of global variables.
I recently came to a similar answer/question on my own. This is what I did, in case anyone is interested:
<?php
namespace Library;
// Wrapper for \PDO. It only creates the rather expensive instance when needed.
// Use it exactly as you'd use the normal PDO object, except for the creation.
// In that case simply do "new \Library\PDO($args);" with the normal args
class PDO
{
// The actual instance of PDO
private $db;
public function __construct() {
$this->args = func_get_args();
}
public function __call($method, $args)
{
if (empty($this->db))
{
$Ref = new \ReflectionClass('\PDO');
$this->db = $Ref->newInstanceArgs($this->args);
}
return call_user_func_array(array($this->db, $method), $args);
}
}
To call it you only need to modify this line:
$DB = new \Library\PDO(/* normal arguments */);
And the type-hinting if you are using it to (\Library\PDO $DB).
It's really similar to both the accepted answer and yours; however it has a notably advantage. Consider this code:
$DB = new \Library\PDO( /* args */ );
$STH = $DB->prepare("SELECT * FROM users WHERE user = ?");
$STH->execute(array(25));
$User = $STH->fetch();
While it might look like normal PDO (it changes by that \Library\ only), it actually doesn't initialize the object until you call the first method, whichever it is. That makes it more optimized, since the PDO object creation is slightly expensive. It's a transparent class, or what it's called a Ghost, a form of Lazy Loading. You can treat the $DB as a normal PDO instance, passing it around, doing the same operations, etc.
There are a few basic flaws in your setup:
The configure.php file shouldn't be in the web server's document root — if the server is ever missconfigured you might expose credentials to the public. You might think it won't happen to you, but it's a risk you just don't need to be taking. Classes also shouldn't be there... this isn't as important but still anything that doesn't need to be public shouldn't be public.
Unless you're working with an especially large project, you shouldn't have an "initialization" directory. Loading one large file is approximately 10x faster than loading ten small files with the same contents. This tends to really add up as a project grows and can really slow down PHP sites.
Try not to load things unless you actually need to. For example don't connect with PDO unless you actually need to. Don't session_start() you actually read/write to session. Don't include a class definition file unless you create an instance of the class. There are limits to how many connections you can have. And APIs like session establish "locks" that can pause code execution for other people using the same resource.
As far as I can tell, you're not using Composer. You should be using it - it'll make life so much easier both for your own code and for third party dependencies.
Here's my proposed directory structure, which is similar to what I use for medium sized projects:
init.php Replaces public_html/initialize. Your PDO connection details
are held here.
classes/ Replaces public_html/classes
vendor/autoload.php Your class autoload script generated using the
industry standard Composer command line tool
composer.json The file where you describe how autoload.php
operates among other things. For example if you
don't use namespaces (maybe you should) it might be:
{"autoload": {"psr-4": { "": "classes/" }}}
public_html/index.php Your landing page
public_html/other.php Some other page
public_html/css/foobar.css ...and so on for all static resources
The init.php file might look something like:
date_default_timezone_set('Etc/UTC');
require 'vendor/autoload.php';
$pdoConnect = function() {
static $pdo = false;
if (!$pdo) {
$pdo = new PDO('mysql:dbname=db;host=localhost', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
return $pdo;
};
// similar anonymous functions for session_start(), etc.
index.php might look like:
require '../init.php';
$pdo = $pdoConnect();
// go from there
other.php might be similar but maybe it doesn't connect to the database, therefore doesn't execute $pdoConnect.
As much as possible, you should write the bulk of your code into the classes directory. Keep index.php, other.php, etc as short and sweet as possible.
$dsn = 'mysql:host=your_host_name;dbname=your_db_name_here'; // define host name and database name
$username = 'you'; // define the username
$pwd='your_password'; // password
try {
$db = new PDO($dsn, $username, $pwd);
}
catch (PDOException $e) {
$error_message = $e->getMessage();
echo "this is displayed because an error was found";
exit();
}

PHP PDO class construction

I'm pretty new to both PDO and OOP. I'm trying to write a class that connects to a database and updates inserts and modifies it. I have several questions:
Is it good practices to connect to the database in the constructor?
Should the one class be updating, inserting, modifying and connecting or should it be split up into several classes?
Why is runQuery not working? I assume its because $pdo is defined in a different scope. How would I get this working?
If the class is include at the top of every page does that mean it will reconnect to the database every time a new page is loaded and will that cause security issues?
Apologies for the overload of questions. Thanks in advance for any answers.
<?php
class Login{
private $_username;
private $_password;
private $_host;
private $_database;
private $_driver;
//Connect to the database
function __construct($configFile){
$connectionDetails = parse_ini_file($configFile);
$this->_username = $connectionDetails['username'];
$this->_password = $connectionDetails['password'];
$this->_host = $connectionDetails['host'];
$this->_database = $connectionDetails['database'];
$this->_driver = $connectionDetails['driver'];
$pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
}
public function loginAllowed($user, $pw){
$sth = $pdo->setFetchMode(PDO::FETCH_ASSOC);
print_r($sth);
}
public function runQuery($query, $params){
$sth = $this->pdo->prepare($query);
$sth->execute($params);
}
}
Because $pdo is a local variable in your constructor and your method loginAllowed. You should make it an instance variable (private $pdo) so you can call it through $this->pdo. I also suggest to use type hinting here, give the PDO class as a parameter in the constructor.
Example
<?php
class Login {
private $pdo;
// Your other instance variables
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
// Your other methods
}
$pdo = new PDO("...");
$login = new Login($pdo);
You shouldn't bother your class with reading settings and initialising your database connection (definitely read about separation of concerns), keep it out of your class. Just give the PDO object as a parameter (I used type hinting, that way you are forced to provide an object of the PDO type). Another advantage is that you can now make sure you have only one active database connection (you can manage this in your code base), creating multiple connections is unnecessary and definitely unwanted (performance wise).
Also use require_once to include your class definition. Otherwise you will get many errors about redeclaring (and you'd want to avoid that).
Connect to the db wherever you find it most convenient. Just try to make sure there's only ONE connection. More connections to the same db is a waste of time and resources.
The class you refer to is called a model in the MVC architecture. It usually does all the operations on a given table. I see nothing wrong in using a single class for all your needs - as long as the code is readable and maintainable.
It's not working because $pdo is a local variable. In the ctor, instantiate $this->pdo instead.
Including a class is not equivalent to instantiating it. A new instance will make another connection. Including it multiple times will only give you a multiple declaration error :). Use require_once instead. If you wish to use the instance in multiple files, I strongly suggest you do a quick search regarding the Singleton pattern. Using a singleton object will ensure you always have only one instance of your model object.
Don't bother with all the random stuff, just replacethis in your construct:
$pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
with
$this->pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
and reference it as $this->pdo from now on. As simple as that!!
1) Is it good practices to connect to the database in the constructor?
No good.just connect befor query
if($this->pdo == null) {
$this->pdo = new PDO("....");
}
2) Should the one class be updating, inserting, modifying and connecting or should it be split up into several classes?
Add methods for class
3) Why is runQuery not working? I assume its because $pdo is defined in a different scope. How would I get this working?
use $this->pdo instead
4) If the class is include at the top of every page does that mean it will reconnect to the database every time a new page is loaded and will that cause security issues?
use static $pdo
then self::$pdo would be the only one connector
if(self::$pdo == null) {
self::$pdo = new PDO("....");
}

Categories