I have started to learn how to use OOP and have created a user authorisation class to check if the user exists etc. Currently I am connected to the database by using the global variable $dbh which is a PDO connection. I've heard that using global variables in this way isn't good practice but am not sure how I can improve it, would I just pass the $dbh variable into the method that requires it when connecting to a database and why exactly is this not considered good practice?
Here is some code I am using:
Database PDO connection included in calling program:
//test the connection
try{
//connect to the database
$dbh = new PDO("mysql:host=localhost;dbname=oopforum","root", "usbw");
//if there is an error catch it here
} catch( PDOException $e ) {
//display the error
echo $e->getMessage();
}
The class that requires the database connection:
class Auth{
private $dbh;
function __construct(){
global $dbh;
$this->dbh = $dbh;
}
function validateLogin($username, $password){
// create query (placing inside if statement for error handling)
if($stmt = $this->dbh->prepare("SELECT * FROM oopforumusers WHERE username = ? AND password = ?")){
$stmt->bind_param(1, $username);
$stmt->bind_param(2, $password);
$stmt->execute();
// Check rows returned
$numrows = $stmt->rowCount();
//if there is a match continue
if( $numrows > 0 ){
$stmt->close();
return TRUE;
}else{
$stmt->close();
return FALSE;
}
}else{
die('ERROR: Could not prepare statement');
}
}
function checkLoginStatus(){
if(isset($_SESSION['loggedin'])){
return TRUE;
}else{
return FALSE;
}
}
function logout(){
session_destroy();
session_start();
}
}
You should pass the PDO connection to the constructor:
function __construct($dbh) {
$this->dbh = $dbh;
}
The connection is called a dependency of your class because obviously your class needs it in order to carry out its function. Good practice dictates that your class should make it explicit that this dependency exists; this is achieved by making it a mandatory constructor parameter.
If you instead pull in the dependency from a global variable you create several issues:
It's not clear at all to a user of your class that there is a dependency in the first place
Your class is now coupled to the global variable, which means that the variable cannot be removed or renamed without breaking the program
You have created the preconditions for "action at a distance": modifying the value of the global variable causes another (seemingly unrelated) part of your application to change behavior
You can simply pass it to constructor.
function __construct($connection){
$this->connection = $connection;
}
When you create object you do:
$obj = new Class($dbh);
Pass the database object in via the constructor. PHP's object model means that = creates new references to the same instance of an object.
class ThingThatDependsOnDatabase
{
private $db = NULL;
public function __construct (PDO $db)
{
$this -> db = $db;
}
public function selectSomething ($id)
{
$sql = 'SELECT * FROM table WHERE id = ?;'
$this -> db -> prepare ($sql);
// And so on
}
}
This is an example of a pattern called Dependency Injection, because the things your class depend on are injected via a method (setter, constructor, etc).
Related
Ok,
This is sort of an involved problem, but any help or advice would be incredibly appreciated.
So I'm working with a site that (using .htaccess) redirects all traffic to a load.php. For any sql functionality, I have an abstract class that has a lot of query statements as functions that pass parameters to define the specifics of each query.
e.g.
$table->update("constraints")
I'm trying to figure out how to set the connection to the database on load.php, and then set the connection as a variable ($mysqli) that can then be referenced in my abstract query class without having to pass the parameter to every single query function call.
Again, any help or advice would be appreciated.
Here's an example of a function:
function clearTable (){
$mysqli = dbConnect::connect();
$sql = "TRUNCATE TABLE $this->tablename";
$mysqli->query($sql);
}
If I connect to the database in a construct function and set $this->mysqli and replace $mysqli = dbConnect::connect(); with $mysqli = $this->mysqli, none of the queries work. Though they work with a fresh reconnect on each call.
You should use Dependency Injection for this.
Basically it means that the class that needs the database connection doesn't create the connection, it just receives the already instasiated instance.
Example
In some init file:
// Create the db connection
$db = new Mysqli(......);
// Pass it to the query class that needs it
$queryClass = new QueryClass($db);
Then in your class file:
class QueryClass
{
protected $db;
public function __construct($db)
{
// $this->db will now be the same Mysql instance
$this->db = $db;
}
public function doSomeQuery()
{
$this->db->query(....);
}
}
A bonus for this is that you don't need to touch the QueryClass, if you ever want to start making some unit tests. You only need to pass a DB connection to a test database instead.
After looking through this a bit more, I can also create my db::connect() function to look like this:
class dbConnect {
private static $db;
private $mysqli;
private function __construct() {
$this->mysqli = new mysqli(HOST, USER, PASSWORD, DATABASE);
}
function __destruct() {
$this->mysqli->close();
}
public static function connect() {
if (self::$db == null) {
self::$db = new dbConnect();
}
return self::$db->mysqli;
}
}
and pass that as $this->mysqli in the query functions file
I have a PHP app that uses 2 different databases. The connection is realized by a singleton mysql class. What I would like to achieve is to use the same class but to connect to another database depending on a variable stated when calling the class.
So, the code used (but not yet functional):
/ start the single class
class Singleton {
// declare two private variables
private static $_instace;
private $conn;
var $dbc = 0;
// declare private constructor class
private function __construct() {
$this->conn = mysql_connect(HOST, USER, PASS);
//die('DB State: [' . $this->dbc . ']');
if ($this->dbc) {
mysql_select_db(DB_DATABASE_PS);
} else {
mysql_select_db(DBNAME);
}
}
// create a singleton method
public static function getconnect($dbc = false) {
if (!self::$_instace) {
self::$_instace = new Singleton();
$_instace->dbc = $dbc;
} else {
$_instace->dbc = $dbc;
}
return self::$_instace;
}
}
When calling a class that uses the first database (DBNAME), it all works perfect but when trying to use the second database, the code doesn't help me at all.
The code to load the second database inside a new class is made trough this code:
public function __construct() {
$this->connect = Singleton::getconnect(true);
}
Could someone help me figure it out?
Thank you!
The problem is, you're selecting the database during the construction of the object(in __construct() method) and it's completely based on the class member variable $dbc. So the next time you want to change the database, you have to call getconnect() method like this, Singleton::getconnect(true);, and then create another object to change the database, which would eventually defeat the purpose of singleton pattern. So basically, every time you change the database you have to call getconnect() method with true and false parameter alternatively, and create a new object to change the database.
Now comes down to your problem,
how should I use it (the singleton class) to change between the databases, keeping in mind that on a single page there could be data from both databases
Use the following code snippet to implement singleton pattern and change databases using a single object.
class Singleton {
// declare two private variables
private static $instance;
private $conn;
// Since it's constructor method is private
// it prevents objects from being created from
// outside of the class
private function __construct() {}
// It creates an object if not previously created,
// opens a connection to MySQL Server
// and returns the object
public static function getInstance() {
if(!isset(self::$instance)){
self::$instance = new Singleton();
self::$instance->conn = mysql_connect(HOST, USER, PASS);
}
return self::$instance;
}
// set your database here
public function setDatabase($db){
return mysql_select_db($db, $this->conn);
}
// Execute your query here
public function executeQuery($query){
return mysql_query($query, $this->conn);
}
// Close your connection here
public function closeConnection(){
mysql_close($this->conn);
}
}
// Get an instance of Singleton class
$obj = Singleton::getInstance();
// Set database "abc"
if($obj->setDatabase("abc")){
echo "database has changed <br />";
}else{
echo "database has not changed <br />";
}
// Display the selected database
$resultset = $obj->executeQuery("SELECT DATABASE() as db");
$row=mysql_fetch_assoc($resultset);
echo $row['db'] . "<br />";
// Set database "def"
if($obj->setDatabase("def")){
echo "database has changed <br />";
}else{
echo "database has not changed <br />";
}
// Display the selected database
$resultset = $obj->executeQuery("SELECT DATABASE() as db");
$row=mysql_fetch_assoc($resultset);
echo $row['db'] . "<br />";
// close connection
$obj->closeConnection();
Output:
database has changed
abc
database has changed
def
Sidenote: Please don't use mysql_ database extensions, they were deprecated in PHP 5.5.0 and were removed in PHP 7.0.0. Use mysqli or PDO extensions instead. And this is why you shouldn't use mysql_ functions.
I have the following code which consists of class DB that establishes a connection with the SQL database using mysqli.
<?php
class DB
{
private $mysqlilink;
private $errors;
function __construct($errors = array())
{
$this -> errors = $errors;
$this -> connect();
}
function connect()
{
$server = "127.0.0.1";
$user_name = "un";
$password = "pw";
$database = "db";
if ($this -> mysqlilink == null)
{
$this -> mysqlilink = new mysqli($server, $user_name, $password, $database);
if (mysqli_connect_errno())
{
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
}
return $this -> mysqlilink;
}
function __destruct()
{
$stmt -> close();
}
}
?>
I have plans to use at least one class (in its own script file) with dedicated PHP functions that access the database for various parts of the website. After importing this script above, how do I link to it and make a call to the database through the object's connection? I am using the following code:
<?php
include_once("connect.php");
class PageFunctions
{
function printText()
{
if ($stmt = $this -> mysqlilink -> prepare("SELECT Text, MoreText FROM mytext WHERE id = 1"))
{
$stmt -> execute(); $stmt -> store_result();
$rows = $stmt -> num_rows;
if ($rows == 0) { return 'Database Not Found'; }
else
{
$stmt -> bind_result($returnedText, $moreReturnedText); // Output variable(s)
while ($stmt -> fetch()) // Return results
{
return 'First text: ' . $returnedText . ' Second text: ' . $moreReturnedText;
}
}
$stmt -> free_result();
return;
}
else { printf("Prepared Statement Error: %s\n", $this -> mysqlilink -> error); }
}
}
?>
To reiterate, I need to use the first code sample as a class that forms an object in multiple other classes/code files like the second code sample. Since I am new to PHP object orientation I was unable to successfully accomplish this, so I thought I'd ask for some expert advice before I come up with a bad solution.
It sounds like you're looking for Dependency Injection. There are other ways, but this is the best practice.
//create an object of the DB class
$DB = new DB();
//create a PageFunctions object and pass the DB object into it as a dependency
$PF = new PageFunctions($DB);
//call your function from PageFunctions
$PF->myFunction();
//follow these concepts and do whatever you want!
You can make this work by setting a constructor for PageFunctions:
class PageFunctions() {
//we don't want to accidentally change DB, so lets make it private;
private $DB;
//this is the class constructor
//the constructor is called when instantiating the class - new PageFunctions()
public function __construct(DB $DB) {
//now the DB object is available anywhere in this class!
$this->DB = $DB;
}
//sample function
public function myFunction() {
$this->DB->connect();
}
}
So, anytime you need to use a class within another class, make an instance (object) of it (or use an existing one) and pass it into the new class that needs it when creating an instance of it.
You might see this behavior accomplished using a Dependency Injection container, but it is still the same concept, system, and result. It's just a bit more abstracted. As you might have noticed from my explanation there, if you have a lot of classes that depend on other classes, that depend on other classes, etc, it can get quite overwhelming manually creating the instances and passing them in. A dependency injection container is nice because it lets you tell it how to make each class, and then it will take care of putting them altogether.
I have a class called DB (class.pdo.php) that does all the handling on mysql queries using PDO and another class called user that I use to manage a login system.
My question relates to always having to instantiate the $db in every public function of users so I can use DB. Is this efficient? Shouldn't I be instantiating DB inside the __construct() of users?
This is my code
require_once("../../class.pdo.php");
class user {
private $db = null;
public function __construct(){
/* Empty? */
}
public function find_by_email($email){
$db = new db();
$db->query('SELECT * FROM users WHERE email = :email LIMIT 1');
$db->bind(':email',$email);
$result = $db->single();
return $result;
}
public function create($email,$password,$first_name,$last_name){
$db = new db();
$db->query("INSERT INTO users(email,password,first_name,last_name,created_at) VALUES (:email,:password,:first_name,:last_name,NOW())");
$db->bind(':email',$email);
$db->bind(':password',$password);
$db->bind(':first_name',$first_name);
$db->bind(':last_name',$last_name);
$result = $db->execute();
return $db->lastInsertId();
}
[more similar functions ommited]
Well, despite of some comments suggesting the use of the Singleton pattern, I totaly disagree in using it for this purpose.
Your application will not always use a single connection to just one database.
Let me show you how I'd do this:
class DbConnector {
private $dbh;
private $dsn;
public function __construct($dsn) {
$this->dsn = $dsn;
}
private function connect() {
if($this->dbh === null) {
$this->dbh = new PDO($this->dsn);
}
}
public function disconnect {
if($this->dbh !== null) {
$this->dbh = null;
}
}
public function query($sql) {
$this->connect();
//... do the rest
}
public function fetchAll($sql) {
$this->connect();
//... do the rest
}
public function insert($table, $values) {
$this->connect();
//... do the rest
}
public function update($table, $values, $cond) {
$this->connect();
//... do the rest
}
public function delete($table, $cond) {
$this->connect();
//... do the rest
}
}
class User {
private $dbConn;
public function __construct(DbConnector $dbConn) {
$this->dbConn = $dbConn;
}
public function create($email,$password,$first_name,$last_name){
$this->dbConn->query("INSERT INTO users(email,password,first_name,last_name,created_at VALUES (:email,:password,:first_name,:last_name,NOW())");
$this->dbConn->bind(':email',$email);
$this->dbConn->bind(':password',$email);
$this->dbConn->bind(':first_name',$email);
$this->dbConn->bind(':last_name',$email);
$this->dbConn->execute();
return $this->dbConn->lastInsertId();
}
// ...
}
Results:
No singleton used = testable.
Connection to the database is just openned when needed
Your connection is persistent. If you open and close connections in every method, you loose the capability of creating transactions.
What about using the Singleton pattern to create one object for the connection and use it everytime you need it, instead of creating new objects all the time?
I would do something similar with lazy loading: don't initiate in the constructor unless you're sure you actually need the connection every time an object is created but absolutly don't create a new object on each method call. Instead, save the resulting object into an object var which is checked on each method call and initiates the connection if missing.
class user {
protected $_db = null;
private function _init_db() { $this->_db = new XXX; }
public function create( $x, $y, $z ) {
if ( ! $this->_db ) $this->_init_db();
# use $this->_db ..
}
public function find_by_email( $x, $y, $z ) {
if ( ! $this->_db ) $this->_init_db();
# etc
}
}
This has the advantages of avoiding global static state (singletons..) and only creates the connection / object at the very last moment so you're sure you actually need it and it's not just a useless connection.
Speaking of efficiency, the main problem with your code is that it establishes new connection for the every method called. This one is indeed inefficient to the point of killing your database server. And it's incomparable to the other problem you have.
So, in general, you can have whatever way you want - either get somehow an instance of db class in the every function or use a class variable - but either way have to use single PDO instance throughout whole application.
Also I find your functions quite inefficient from the amount of code point of view, and would have optimized them this way
public function create($email,$password,$first_name,$last_name){
$sql = "INSERT INTO users(email,password,first_name,last_name,created_at) VALUES (?,?,?,?,NOW())";
$this->db->query($sql);
$result = $db->execute(func_get_args());
return $db->lastInsertId();
}
From a object point of view, I'd leave database instantiating within the methods, rather than an entire class.
Each method should only see the variables and data it needs, in order to perform its function.
For instance, a createUser() method would need to see variables or properties such as $username, $usergroupId, as well as $database etc.
However, you may have a function which is called randomPassword(), which generates a random password from numbers and letter.
This randomPassword() function doesn't need the database object and therefore, an already initialised database connection in the object scope would be wasteful.
It would be better only to create the new database object in methods that required it.
In addition, in my application, I don't create a new database connection each time I used new database. Instead, I've opted for a singleton PDO database object which keeps the connection active.
I can then just call the database object statically to retrieve an existing connection. Therefore, if, in the process of running my application I need to have 20 database objects, my application then only returns the same object, and the same connection.
I am trying to convert code from mysql to mysqli.
The code uses a single mysql_connect in a file which is included by every other file.
mysql_connect returns a MySQL link identifier that is a superglobal so you can rely on having a database connection available in any of your own functions.
It looks like with mysqli_connect this is not the case, the object returned isn't global.
Does this mean I have to add : global $mysqli; at the top of every function, or is there an way of making it a superglobal?
Relying on the fact that PHP will use the last opened connection resource if you don't specify one, is probably not a very good idea.
What happens if your application changes and you need two connections, or the connection is not there?
So it seems you need to do some refactoring anyway.
Here's a solution similar to Karsten's that always returns the same mysqli object.
class DB {
private static $mysqli;
private function __construct(){} //no instantiation
static function cxn() {
if( !self::$mysqli ) {
self::$mysqli = new mysqli(...);
}
return self::$mysqli;
}
}
//use
DB::cxn()->prepare(....
I usually make a function:
$mysqli = new mysqli(...);
function prepare($query) {
global $mysqli;
$stmt = $msqyli->prepare($query);
if ($mysqli->error()) {
// do something
}
return $stmt;
}
function doStuff() {
$stmt = prepare("SELECT id, name, description FROM blah");
// and so on
}
and then call that. That being said, I've since abandoned mysqli as being too bug-ridden to be considered usable. Shame really.
A very simple way to do this would be with a fixed database class, just to hold the mysqli connection object:
class Database {
public static $connection;
}
Database::$connection = new mysqli(HOST, USERNAME, PASSWORD, DATABASE);
Then you can access it in the normal ways:
$sql = 'SELECT * FROM table';
$result = Database::$connection->query($sql);
$result = mysqli_query(Database::$connection, $sql);
echo 'Server info ' . mysqli_get_server_info(Database::$connection);
To introduce some oop to you and solve your problem, you could use a class like this:
class MyDatabase
{
private static $_connection;
public static function connect()
{
$mysqli = new mysqli(...);
self::$_connection = $mysqli;
}
public static function getConnection()
{
return self::$_connection;
}
}
In your database-connection file you would load this class and execute MyDatabase::connect(); once.
To get the $mysqli-connection anywhere in your script, just call MyDatabase::getConnection();.