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.
Related
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.
I have class, where i make connection to database and do some queries.
But i can't make query to this database from other class. Problem is that class Cd can't see db connection command -> can't make a query. Here is the code:
require_once('config.php');
class myClass
{
public $mysqli;
public $res;
function connect()
{
$database = new Database();
$this->mysqli = new mysqli($database->db_host, $database->db_user, $database->db_pass, $database->db_table);
}
function cd($id)
{
......
}
}
}
class Cd extends myClass
{
function cdname($id)
{
$get= new Scandiweb();
$get->mysqli;
$this->res = $get->mysqli->query("SELECT * FROM disk WHERE id=" . $id . "");
if ($this->res->num_rows > 0) {
.........
}
}
}
Your code is a bit messy, so it's hard to tell where exactly the problem lies:
Why do you require config?
Why do you create a Database (which is more like a DbConfig) in the constructor instead of passing it?
What is the Scandiweb-class?
Why do you call mysqli->query on that class instead of $this
The last one is your immediate mistake. You extend myClass which creates the mysqli-connection and stores it as class variable $this->mysqli. That means that the child class Cd will have access to it. When you extend a class you can call all it's public and protected properties and methods. Only those marked as private can't be accessed.
That means instead of accessing $get->mysqli->query(...) you can do $this->mysqli->query(...). What would make sense in OOP is to create a connection once (like you do in the constructor) and pass it around to the services requiring a database connection. This is called Dependency Inversion Principle and using a Dependency Container makes it easier (but is not mandatory).
There are so called design patterns that will make it easier to deal with performing sql queries like in your code above. The most common ones are the Active Record-pattern as used in Laravel's Eloquent and the Propel library, the Table Data Gateway-pattern as used in Zend Framework's DB-component and the Data Mapper-pattern as employed by Doctrine ORM. If you want to write OOP code you should look at their documentation and maybe use one of those instead of dealing with everything yourself.
I'm trying to create a pagination class and use a variable from outside the class.
But it's giving me the fatal error "Call to a member function query() on a non-object".
This is the index file:
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new pagi();
$records = $pagination->get_records("SELECT * FROM `table`");
And this is the pagi.php file:
class pagi {
public function get_records($q) {
$x = $db->query($q);
return $db->fetch($x);
}
}
Is it possible to use this variable from out side of the class inside the class, without creating a new one inside the class?
The correct way to solve this would be to inject the database object into the other class (dependency injection):
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new Paginator($db);
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`");
class Paginator
{
protected $db;
// Might be better to use some generic db interface as typehint when available
public function __construct(DB_MySQL $db)
{
$this->db = $db;
}
public function get_records($q) {
$x = $this->db->query($q);
return $this->db->fetch($x);
}
}
Another way you could solve it is by injecting the instance of the database class into the method that uses it:
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new Paginator();
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`", $db);
class Paginator
{
public function get_records($q, DB_MySQL $db) {
$x = $db->query($q);
return $db->fetch($x);
}
}
Whichever method you choose depends on the situation. If only one method needs an instance of the database you can just inject it into the method, otherwise I would inject it into the constructor of the class.
Also note that I have renamed your class from pagi to Paginator. Paginator is a better name IMHO for the class because it is clear for other people (re)viewing your code. Also note that I have made the first letter uppercase.
Another thing I have done is changed the query to select the fields you are using instead of using the "wildcard" *. This is for the same reason I have changed the classname: People (re)viewing your code will know exactly what fields will be retrieved without checking the database and/or the result.
Update
Because answer gave rise to a discussion regarding why I would go the dependency injection route instead of declaring the object global, I would like to clarify why I would use dependency injection over the global keyword: When you have a method like:
function get_records($q) {
global $db;
$x = $db->query($q);
return $db->fetch($x);
}
When you are using the above method somewhere it isn't clear that the class or method uses depends on $db. Hence it is a hidden dependency. Another reason why the above is bad is because you have tightly coupled the $db instance (thus the DB_MySQL) class to that method / class. What if you need to use 2 databases at some point. Now you would have to go through all code to change global $db to global $db2. You should never need to change your code just to switch to another database. For this reason, you should not do:
function get_records($q) {
$db = new DB_MySQL("localhost", "root", "", "test");
$x = $db->query($q);
return $db->fetch($x);
}
Again, this is a hidden dependency, and tightly couples the DB_MySQL class to the method / class. Because of this it is also impossible to properly unit test the Paginator class. Instead of testing only the unit (the Paginator class) you are also testing the DB_MySQL class at the same time. And what if you have multiple tightly coupled dependencies? Now you are suddenly testing several classes with your so called unit tests. So when using dependency injection you can easily switch to another database class, or even a mocked one for testing purposes. Besides the benefit of testing only one unit (you don't have to worry about getting wrong results because of dependencies) it will also make sure your tests will finish fast.
Some people may think the Singleton pattern is the correct way to get access to a database object, but it should be clear, having read all of the above, a singleton is basically just another way of making things global. It might look different, but it has the exact same characteristics and hence the same problems as global.
Although I do agree that the dependency model is nice, for the database, I personally use a static connection that is available to all instances of the database class and the create instances to query whenever I need one. Here is an example:
<?php
//define a database class
class DB {
//the static connection.
//This is available to all instances of the class as the same connection.
private static $_conn;
//store the result available to all methods
private $result;
//store the last query available to all methods
private $lastQuery;
//static connection function. connects to the database and stores that connection statically.
public static function connect($host, $user, $pass, $db){
self::$_conn = mysqli_connect($host, $user, $pass, $db);
}
//standard function for doing queries. uses the static connnection property.
public function query($query){
$this->lastQuery = $query;
$this->result = mysqli_query(self::$_conn, $query);
//process result, return expected output.
}
}
//create connection to the database, this connection will be used in all instances of DB class
DB::connect('local', 'DB_USER', 'DB_PASS');
//create instance to query
$test = new DB;
//do query
$test->query("SELECT * FROM TABLE");
//test function
function foo(){
//create instance to use in this function
$bar = new DB;
//do query
$bar->query("SELECT * FROM OTHER_TABLE");
//return results
return $bar->fetchArray();
}
That way I can create all the instances I want of DB within any function, method...etc and use that local instance of the class to do all my queries. All instances use the same connection.
One thing to note though is that this only allows for one connection to the database per defined class but I only use one so this isn't an issue for me.
you could add the db-connection ($db) to the call of the get_records method:
Here are only the relevant lines of code:
First file:
$records = $pagination->get_records("SELECT * FROM `table`", $db);
Second file:
public function get_records($q, $db) {
The other answers thus far are definitely preferable to using a global since that will ruin your encapsulation (eg you'd need to have that object defined prior to calling that method).
It's much better to enforce that in the method signature or not use a class.
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();
}
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("....");
}