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.
Related
struggling to grip the varying levels of variables in OOP PHP. I want to have one connection file which can be accessed from all classes and functions through out my project. I include 'config.php' but the $mysql variable cannot be found. Any help greatly appreciated;
I have a file
config.php
public $mysqli = new mysqli('localhost', 'usernameEG', 'passwordEG', 'databaseEG');
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
and a few class files
class.User.php
<?php
class User {
private $mysqli = null;
function __construct(){
//=========
//include config.php here?
}
function myProfile($Id){
$stmt = $this->mysqli->prepare("SELECT First_Name, Last_Name, Email, DateJoined FROM members WHERE Id = ? ");
$stmt->bind_param('i',$Id);
$stmt->execute();
$stmt->bind_result($fname,$lname,$email,$date);
$stmt->store_result();
$stmt->fetch();
echo "<p>User#: ".$Id."</p>";
echo "<p>First Name: ".$fname."</p>";
echo "<p>Last Name: ".$lname."</p>";
echo "<p>Email: ".$email."</p>";
echo "<p>Date Joined: ".$date."</p>";
$stmt->close();
}
function example(){
EXAMPLE CODE HERE WILL ALSO NEED TO BE ABLE TO USE SAME CONNECTION
}
}
So rather than a singleton approach as hinted at in the other answer. Let me offer you a dependency injection approach. For a lot of experienced developers, dependency injection is a preferred approach, as it allows the class receiving the dependency to have looser coupling to the dependency (for example, you don't need to even know the name of the class for instantiating the dependency like you would with a singleton approach). You just need to know that the dependency being passed meets some interface requirement (i.e. it implements some interface or is a certain type of class).
So that would look more like this:
class User {
protected $mysqli = null;
// other properties
public function __construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
// other constructor operations
}
// other methods
}
So what is happening here? Here you enforce the requirement to pass an object of type mysqli when instantiating this class. This could be a mysqli object or perhaps even your own custom class which extends mysqli, the User class doesn't care, so long as all mysqli class methods are implemented
Usage could be like
require('/path/to/db_config.php'); // an include which creates a mysqli object or provides a factory for one, or whatever
$user = new User($mysqli);
$user->foo(); // do something
Interestingly enough, you might at times see use of singelton pattern along with dependency injection. So say you had a mysqli_singleton_factory class with singleton functionality to provide you the single instantiated mysqli object. The usage might look like this:
require('/path/to/db_config.php'); // an include which provides a singleton
$user = new User(mysqli_singleton_factory::get_instance());
$user->foo(); // do something
$other_class = new other_class_requiring_mysqli(mysqli_singleton_factory::get_instance());
$other_class->bar(); // do something
Here you have both guaranteed that you only have one instantiated mysqli object during script execution AND you have decoupled your User class from having to do any instantiation of the object itself.
For reference, a singleton pattern may look like this:
class mysqli_singleton_factory {
protected static $mysqli = null;
protected function __construct() {
// assume DB connection setting have been pre-defined as constants somewhere
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// make sure connection worked
if($mysqli->connect_error) {
throw new Exception(__METHOD__ . ' at line ' . __LINE__ . ' failed with: ' . $mysqli->connect_error);
}
self::mysqli = $mysqli;
}
public static function get_instance() {
if (false === self::mysqli instanceof mysqli) {
self::__construct();
}
return self::mysqli;
}
}
I've done this a number of times previously and I have found that it is easy to implement "singleton-like" class to serve as a database connector which then can be referenced by any object in the application.
config.php
Config.php is where the credentials are set and the database class is actually constructed.
$dbHost = 'localhost';
$dbUser = 'someUser';
$dbPass = 'somePass';
$dbSchema = 'someSchema';
Database::$db = new MySQLi($dbHost, $dbUser, $dbPass, $dbSchema);
classes.php
classes.php is where my classes are defined, which is kept separate from the rest of the code.
class Database {
public static $db;
}
class User {
...
function example()
{
$stmt = Database::$db->prepare('SELECT TRUE');
...
}
}
index.php
index.php is the entry point for the app, and is used to handle the request and exhibit the desired behavior using the supplied classes.
require_once('classes.php');
require_once('config.php');
/* Application Goes Here */
This ensures that all objects in my project use the same connection, I only have to invoke it once and I don't have to mess about with scope too much.
So I basically have two files. At the end I would have more, but I would like to create a class called DB that would use PDO database operations, and then I would extend this class to make all of my functions for working with the database. So DB class, would then extend to class dbADD, that would have all the add functions for different database tables.
This is called config.php:
<?php
DEFINE ('DBHOST', 'localhost');
DEFINE ('DBUSER', 'REMOVED');
DEFINE ('DBPSW', 'REMOVED');
DEFINE ('DBNAME', 'REMOVED');
class DB {
public $db;
private static $instance;
public function __constructor(){
$config ['db'] = array(
'host' => DBHOST,
'username' => DBUSER,
'password' => DBPSW,
'dbname' => DBNAME,
);
$this->db = new PDO('mysql:host =' . $config['db']['host'] . ';dbname=' . $config['db']['dbname'],$config['db']['username'],$config['db']['password']) ;
}
public static function getInstance()
{
if (!isset(self::$instance))
{
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
public function GetArticles ($search){
$sql = "SELECT `FirstColumn`, `SrcColumn`, `article` FROM `test_table` WHERE `FirstColumn` = 23";
//$dbs = new DB();
$dbs = DB::getInstance();
$query = $dbs->db->prepare($sql);
//$query->bindValue(':search', $search, PDO::PARAM_INT);
$query->execute();
while ($row = $query->fetch(PDO::FETCH_OBJ)) {
// = $row['article'],'</br>';
$return = $row['article'];
}
return $return;
}
}
?>
This file is my test file, which is not that important just a testing-ground. Called test.php:
<?php
require_once('app_core/config.php');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<link rel="stylesheet" href="/style/style.css" type="text/css" media="screen" />
</head>
<body>
<?php
$db = new DB();
//echo $db->db;
//echo $db->GetTestDB();
//$test = $db->TestThis();
//print_r($test);
echo $db->GetArticles('23');
?>
</body>
</html>
If it is possible I also have two other concerns: the first question is a matter of securit -- is this a good practice or not? The other question is how do I hide files with this password data, so I can use them but no one can read them?
Ok, you've got a lot going on here, so I'll try to address issues one at a time to make this class behave properly and in an object-oriented manner (instead of a collection of not-entirely-related methods).
First, your constructor:
// Make these private, will find out why in a moment...
private $db;
// __construct, not __constructor!!
private function __construct() {
// This whole array doesn't serve any purpose because the constants
// are defined and available in all scopes
// while this array is local to the __construct().
// Just get rid of it and use the
// constants directly in the PDO connection
//$config ['db'] = array(
// 'host' => DBHOST,
// 'username' => DBUSER,
// 'password' => DBPSW,
// 'dbname' => DBNAME,
//);
// Use some error checking when establishing your connection
try {
// Some extra bad whitespace removed around =
$this->db = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPSW);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
}
Next your singleton accessor getInstance().
// No code changes necessary....
public static function getInstance()
{
if (!isset(self::$instance))
{
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
Since you have defined a method to access the class as a singleton, the $db property and the __construct() are made private. At no point will you ever call $DB_class-instance = new DB() to instantiate it, or call $DB_class_instance->db to access the connection directly. Instead, you will call DB::getInstance() to access the singleton instance and your methods like GetArticles() to execute queries.
Now onto your querying method:
public function GetArticles ($search){
// Ok a SQL string, no problem...
$sql = "SELECT `FirstColumn`, `SrcColumn`, `article` FROM `test_table` WHERE `FirstColumn` = :search";
// There's no need for this. You already defined $db as
// a class property, so you should be using $this->db
// $dbs = DB::getInstance();
$query = $this->db->prepare($sql);
// bind the $search input parameter...
$query->bindParam(':search', $search);
// Test for success
if ($query->execute()) {
$row = $query->fetch(PDO::FETCH_OBJ) {
// I suppose you know what you want here. If you're only expecting
// one article, there's no real need for the while loop.
// You can just fetch() once.
$return = $row->article;
// OR.....
// However, if you are expecting *multiple* rows, you should be accumulating them
// into an array like this:
$return = array();
while ($row = $query->fetch(PDO::FETCH_OBJ)) {
// Append to an array
$return[] = $row->article;
// OR to get multiple columns returned as an object...
$return[] = $row;
}
return $return;
}
else {
// Query failed, return false or something
return FALSE;
}
}
Finally your controller code:
// The constructor is private, so you can't do this
// $db = new DB();
// Instead you need to use getInstance()
$db = DB::getInstance();
// Returns an array, so print_r()
print_r($db->GetArticles('23'));
Since we made the class' $db property private, it cannot be accessed outside the class. Therefore you would need to define querying methods similar to GetArticles() for any other queries you plan to run as well. If you think you will need to build ad-hoc queries that are not class methods sometimes, then you can change it to
public $db
Then, you could do things outside the class like the following instead of having to build a class method to do it. You do still need to call getInstance() however.
$dbs = DB::getInstance();
// Run a query via the PDO connection $dbs->db
$result = $dbs->db->query('SELECT * FROM sometable');
Little style issue:
This won't actually cause a problem since identifiers are case-insensitive, but stylistically it is weird. define() is a function call and is usually used lowercase:
define('DBHOST', 'localhost');
define('DBUSER', 'REMOVED');
define('DBPSW', 'REMOVED');
define('DBNAME', 'REMOVED');
About your file security
As long as your web server is correctly configured, no one else can read the files. Provided the web server sends .php files to the PHP interpreter rather than dumping their contents to the browser, the files are safe. If you are on a shared host and the host does not properly segregate your files from other tenants, that is their problem and the only good solution would be to get a better host.
It is wise, however, to store your sensitive files above your web server's document root directory. Then even a misconfigured web server could not accidentally dump their contents to a client. They are only accessible to PHP via include.
As PDO is already an object, maybe you don't need to create a singleton class for it at all.
Instead, make a generic model class which you pass the PDO object to.
<?php
class Model {
private $pdo;
__construct(PDO $pdo) {
$this->pdo = $pdo
}
// generic model methods go here
}
Then you can subclass this and flesh out the functionality for each model that you create.
Usage would be something like:
$PDO = new PDO("mysql:host={DBHOST};dbname={DBNAME}", DBUSER, DBPSW);
$myModel = new MyModel($pdo);
$bob = $myModel->getByName('bob');
$articles = new Articles($pdo);
$recentArticles = $articles->getRecent(new Date());
In regards to security, this article offers some nice general tips, http://www.tuxradar.com/practicalphp/17/0/0. In fact, the entire guide is quite helpful.
Advices:
If possible, don't use inline SQL, because if you change the scheme of your database, let's say you rename a column from foo to bar, you will have to find all the inline SQLs where foo is used and change that to bar.
Your idea is good, to have a general behavior for different action types, but there is no point of implementing it, because this good idea was implemented before. For instance you can try out Flourish, which is an ORM and can help you a lot.
Don't store passwords in separate files if you can store them in databases, but don't forget to encrypt passwords and to use a salt too to improve the encryption.
Sorry for the stupid question am a newbie to oop in php...i have a proble wiriting a mysqli class thet returns a connection handler that enable me the connection handler in other classes/methods. i run a small procedural blog n wanted to convert to oop.
heres a my working code example. please refactor for me where necessary. Thank in advance.
$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
public function getConfig($id, $db_link) // thanks cbuckley
{
$db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
i have defined the constants already and the connection is successful but the select is not working. on the index page this goes
include('inc/dbc.php');
$db = new MyDB();
echo $db->getConfig(1, $db_link);
any help is appreciated
Your question is not very specific, and I have the feeling you're not really aware what your concrete problems are. You've already accept an answer that gives you some code but puts you in the wrong direction as it does not solve your underlying problem and wastes code.
The first thing you should know if you want to make use and benefit of the object oriented interface of PHP's mysqli extension is, that the Mysqli class represents the database connection (the "link" as it was named for a procedural approach) already:
require('inc/dbc.php');
$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
That's already it. Sure you might want to use some error handling here:
if ($dbConnection->connect_error)
{
throw new Exception(
sprintf('(#%d) %s', $dbConnection->connect_errorno,
$dbConnection->connect_error)
);
}
Throwing exception instead of let's say die('message') is done, because you can easily create an exception handler so that you can display a more useful response to the user from within a central place instead of handling each exceptional error-case where it appears (actually at the place where die would be).
You can also log and mail the backtrace so you can fix things more easily. Naturally you do not need to use exceptions, however the rule of thumb is to use die only in scripts you throw away in let's say a week and it does not work well with object oriented design.
As you will need this code anyway in all places where you will need your database connection, you can create your own connection object to bring those parts together as they belong together:
class DatabaseException extends Exception
{
}
class DatabaseConnection extends Mysqli
{
public function __construct($host, $user, $password, $database = "", $port = NULL, $socket = NULL) {
parent::__construct($host, $user, $password, $database, $port, $socket);
$this->throwConnectionExceptionOnConnectionError();
}
private function throwConnectionExceptionOnConnectionError() {
if (!$this->connect_error) return;
$message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);
throw new DatabaseException($message);
}
}
The usage is actually pretty straight forward and very much the same, only the name of the class varies and it's definition needs to be loaded:
require('inc/dbc.php');
require('inc/database.php');
$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
As written, the connection object already represents your database connection. So every part in your application that needs it, has to ask for it. Let's review your example function:
function getOption($id, $db_link)
{
// $db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
I renamed the function and I commented the first line, even this might be what you want. Actually, if that function would be part of the DatabaseConnection object, it could work like this:
class DatabaseConnection extends Mysqli
{
...
public function getOption($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
As this example demonstrates, the database connection is already there. However, this is not advisable. Imagine you not only have options but this and that and such and what not more. You would create one function after the other all in one class. Well for a little application that might even so work right, but imagine more and more. You would get one very large class that is responsible for many things. So it would be bad to do this, even if you can use $this already to prepare the statement.
Also take note that you should prepare statements. This has been answered here numerous times, if you're not used to it, read about it, it's worth the lines. There are better ways to not repeat code (DRY: Don't repeat yourself) while stepping into object oriented (you should even already do this with procedural).
So as to have this all in one class would be a problem, you instead put it in a class of it's own:
class DatabaseModelBase
{
protected $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
protected function prepare($query) {
$connection = $this->connection;
$statement = $connection->prepare($query);
if (!$statement) {
throw new DatabaseException(
sprintf('(%s) %s', $connection->error, $connection->errno)
);
}
return $statement;
}
}
class Option extends DatabaseModelBase
{
public function find($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
}
This has some extended error handling again, because most often mistakes are made in the SQL query. And as you can see the individual function to fetch some specific data is placed in it's own class. You can use such classes to group the fetching and updating for specific datatypes.
Usage in full:
$dbConnection = new Connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$option = new Option($dbConnection);
$optionValue = $option->find(1);
echo $optionValue; # value for option with ID1
The names of the Option object probably is not well, I tried to keep the example lightweight but also offer some separation. For other scenarious you might want to prefer some different kind how to access the db connection, because it is injected into Option via it's constructor, Option does not deal any longer with the details how the database connection is being created.
For example you can make the database connection object more smart only to connect to the database the first time prepare or query is actually used with it. So that requests to your website that do not need a database connection would not needlessly connect to the database.
You find more examples in other questions and you might want to learn about dependency injection. Also you always want to keep things apart from each other, so you have some objects that are only lightly connected to each other.
How to successfully rewrite old mysql-php code with deprecated mysql_* functions?
Dependency Injection simple implementation
I would suggest moving the connect to the database also inside the class:
class myDB extends mysqli
{
private $link;
public function Connect()
{
$this->link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
}
public function getConfig($id) // thanks cbuckley
{
$res = mysqli_query($this->link,"SELECT * from config where id='$id'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
And use it like this:
include('inc/dbc.php');
$db = new MyDB();
$db->Connect();
echo $db->getConfig(1);
I recommend you to Wrap the mysqli class in a new Class instead extending it:
For those Classes, where you need the Configuration, just include the Configuration with Dependency Injection. This brings you the Benefit, that the Code, where you need the Configuration, don't need to know about the Way, Configuration get its values.
If you later decide to parse Configuration from a iniFile, you only need to change the Configuration-Class or even better, write a new Class which implements ConfigurationInterface and inject the new ConfigurationClass.
class Configuration implements ConfigurationInterface{
private $mysqli;
public function construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
}
public function get($key)
{
// You should escape this query to prevent SQL-injection
$res = $this->mysqli->query("SELECT * from config where id='$key'");
$row = $res>fetch_array();
return $row['option'];
}
}
interface ConfigurationInterface {
public get($key);
}
Use it like this:
$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);
var_dump($config->get(0));
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).
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();.