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("....");
}
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've just started using PDO and was wondering how best to declare the database connection?
Would it best practice to create a script as follows, called config.php for example
config.php
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
PDO::ATTR_PERSISTENT => true
));
?>
Then have example.class.php
<?php
include config.php;
class Example {
public function fetch() {
$data = $dbh->query('SELECT * FROM myTable WHERE name = ' . $conn->quote($name));
// do stuff
}
}
?>
And do this for all my classes? Or would this make multiple connections? I want to have as few connections as possible.
You're close but your fetch function won't work because $dbh is outside its scope.
You could globalize it but a better solution is to pass your handler to your class upon instantiation
class Example {
/** #var \PDO */
protected $pdo;
public function __construct(\PDO $pdo) {
$this->pdo = $pdo;
}
}
$class = new Example($dbh);
This is a best practice. This way the logistics of setting up and naming your db pointer are irrelevant. Your class defines how it's going to receive it and you use the instance of the pointer you were passed.
Your example looks good, it would only create one persistent connection.
However, you should pass in $dbh to the __construct of Example, and do $this->dbh later instead of relying on $dbh being a global.
To avoid needing to do that in all your classes that need to access, you could either implement a class that deals with the DB and other classes inherit from, or implement a Trait.
To keep clean and organized code, you can create a "DbManager" class and instantiate the PDO, create query and other methods, etc...
You can use the config.php to store your application configuration.
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
I have a class userdb in which I am declaring a function that returns the connection to the database:
return $con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
I have various functions, even across other classes, where I have to access $con (e.g. to pass a query or to fetch data), but I can't access this variable.
Is there a better way to define and use a database class? Remember that I have other classes where I need to access the userdb class.
I would advise you to use the Singleton Pattern for this:
In your userdb class, declare a static property $scon:
private static $scon;
and assuming the function you mention above is named createConnection(), you should create the folowing static method:
public static function connect() {
if (empty(self::$scon)) {
$instance = new userdb();
self::$scon = $indtance->createConnection();
}
return self::$scon;
}
With this, you will be able to access your userdb connection with:
userdb::connect();
Also since this is a singleton, it will only connect once, and use that connection until the end of the script.
Note (on dependency injection): Since #KevinM1 mentioned Dependency Injection, I must add that it is also a possible, and far superior solution. It requires you to create a setConnection() method (or an Abstract ancestor) for all your classes using a database connection, and during the instatiation of these classes you may use a Factory to add the required connection to the object. This should be wrapped inside some class loader, which is avare of your model structure.
See, peace of cake, but for small and fast developement I would stick with the Singleton ;)
If it's in a class, store the instance in a property:
class userDB
{
public $dbCon = false;//because you want to access the instance
//from outside the class, I have made the property public
function connect()
{
$con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
$this->dbCon = $con;
}
}
TO access it outside of the class:
$useDBInstance->dbCon;
return $this->con
return this way from your class and call it this way..
$this->classObject->con->prepare();
Checkout my video tutorial + code for an alternative to global PHP variables.
You're doing it wrong there. You need to use a static variable if you plan to create your connection in a function and store it there. Otherwise you'll keep connecting on every function call. My tutorial explains this very concept of static variables within regular functions.
If it's not clear enough, let me know and I'll try to answer your questions.
Here's some code to accompany this:
/**
* Arguments are none or [$db, [$user, [$pass[, $host]]]].
*
* #return PDO
*/
function PdoDb(){
static $con = null; // I'm explicit :)
// Every time you pass Arguments you reconnect
if(func_num_args()){
$args = array_pad(func_get_args(), 4, null);
list($db, $user, $pass, $host) = $args;
if(empty($user)) $user = 'root';
if(empty($host)) $host = 'localhost';
$con = new PDO("mysql:host={$host};dbname={$db}", $user, $pass);
}
if(empty($con)){
trigger_error('Provide arguments to connect first.', E_USER_ERROR);
return null;
}
return $con;
}
// First run (provide arguments to connect)
PdoDb($db, $user, $pass, $host);
PdoDb($db); // Works if you connect root#localhost with no password
// From here on (it returns PDO)
PdoDb()->DoStuffOfPdo();
Once connected it stays that way. But you can reconnect at will to by providing arguments.
Well, $con will already be an object, as it's instantiating a new PDO object. Unless you're trying to add functionality to your PDO object, wrapping it is pointless.
That said, the best way to share your userdb/PDO object (depending on whether or not you stick with the wrapper) with other objects is to use Dependency Injection. That's a fancy term for passing your db to whatever object needs it. Since objects are defaultly passed by reference in PHP, if you create your db object first, all objects that receive it as a constructor/method argument will be using that same single instance.
EDIT: Link to Dependency Injection implementation
EDIT2: Clarification on DI in small projects -
The normal DI pattern generally requires a special object called a DI Container. This is a special use object that automatically injects the dependency into the object that needs it. For small projects, it's overkill. The simple, low complexity version of DI is simply:
class SomeClass {
protected $db;
public function __construct($db) {
$this->db = $db;
}
}
class SomeClass2 {
public function SomeMethod($db) {
// do something with the db
}
}
$db = new PDO(/* connection string */);
$obj = new SomeClass($db, /* other constructor args */);
// or
$obj2 = new SomeClass2(/* constructor args */);
$obj2->someMethod($db, /* method args */);
The magic is that since objects are passed by reference by default in PHP, $obj and $obj2 are using the same db connection.
The whole idea is to not blow apart scope or encapsulation by having a static method, and to ensure that classes and their methods are up front about what they require in order to work.
Singletons do the exact opposite. They're accessed through static methods, which bypass scope, and since they're invoked and not passed, they never show up in method signatures, so anyone not familiar with the code won't be aware of that hidden requirement. Even Erich Gamma, one of the people who helped codify the Singleton Pattern has regrets about it:
I'm in favor of dropping Singleton. Its use is almost always a design smell.
In PHP, where there's no concept of shared memory, and where scripts execute once per request, the only reason to want to use a singleton is to have easy access to a single resource. Since objects are passed by reference, a single instance can be shared with multiple objects naturally. From there, it's about good design and delegation.
use singlton class implimentation
class connectdb
{
protected static $_instance = NULL;
private function __construct()
{
}
public function getinstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function connect()
{
$this->connection =new PDO("mysql:host=$host;dbname=$db", $user, $pass);
}
}
for using a variable within a class function or independent function you need to place a global keyword
$conn=mysql_connect();
function test(){
global $conn;
}
now $conn will be available within the scope of test function, and it will be available everywhere when defined at the top of the script. For class also you need to do the same thing, make a object of a class and declare it as global within a function
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.