What Is the Best Method for Getting a Database Connection/Object into a Function in PHP

What is the best method for getting a database connection/object into a function in PHP?

I use a Singleton ResourceManager class to handle stuff like DB connections and config settings through a whole app:

class ResourceManager {
private static $DB;
private static $Config;

public static function get($resource, $options = false) {
if (property_exists('ResourceManager', $resource)) {
if (empty(self::$$resource)) {
self::_init_resource($resource, $options);
}
if (!empty(self::$$resource)) {
return self::$$resource;
}
}
return null;
}

private static function _init_resource($resource, $options = null) {
if ($resource == 'DB') {
$dsn = 'mysql:host=localhost';
$username = 'my_username';
$password = 'p4ssw0rd';
try {
self::$DB = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
} elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
self::$$resource = new $resource($options);
}
}
}

And then in functions / objects / where ever:

function doDBThingy() {
$db = ResourceManager::get('DB');
if ($db) {
$stmt = $db->prepare('SELECT * FROM `table`');
etc...
}
}

I use it to store messages, error messages and warnings, as well as global variables. There's an interesting question here on when to actually use this type of class.

How do I pass a database connection into a method PHP

Check the following updated answer. Tested and working.

  <?php

class SomeClass
{

function setDb($servername, $username, $password, $database)
{
// Create the database connection and use this connection in your methods as $this->conn
$this->conn = new mysqli($servername, $username, $password, $database);
if ($this->conn->connect_error) {
die("Connection failed: " . $this->conn->connect_error);
}
echo "New successful connection to myDb \n";
}

public function createTable()
{
// sql to create table
$sql = "CREATE TABLE MyGuests (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(30) NOT NULL,
lastname VARCHAR(30) NOT NULL,
email VARCHAR(50),
reg_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)";

if ($this->conn->query($sql) === TRUE) {
echo "New table created successfully \n";
} else {
echo "Error: " . $sql . "<br>" . $this->conn->error;
}
}
public function normalInsertDb()
{
// sql to insert record using normal query
$sql = "INSERT INTO MyGuests (firstname, lastname, email)
VALUES ('John', 'Doe', 'john@example.com')";

if ($this->conn->query($sql) === TRUE) {
echo "New record inserted successfully using normal sql statement \n";
} else {
echo "Error: " . $sql . "<br>" . $this->conn->error;
}
}
public function preparedInsertDb()
{
// prepare and bind
$stmt = $this->conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
// set parameters and execute
$firstname = "John";
$lastname = "Doe";
$email = "john@example.com";
$stmt->execute();

$firstname = "Mary";
$lastname = "Moe";
$email = "mary@example.com";
$stmt->execute();

$firstname = "Julie";
$lastname = "Dooley";
$email = "julie@example.com";
$stmt->execute();

echo "New records inserted successfully using PREPARED STATEMENTS \n";

$stmt->close();
$this->conn->close();
}
}

$obj = new SomeClass();
$obj->setDb('localhost', 'homestead', 'secret', 'myDb'); //we assume the database myDb exists
$obj->createTable();
$obj->normalInsertDb();
$obj->preparedInsertDb();

My Result:

 my result

Using a Persistent Database Object Connection from Other Objects in PHP

There are a few options, one simple one (and likely the preferred) would be to use a static factory method in your database class that returns a previously initialized instance of the database class.

class Database
{
//static instance of the class
private static $instance;

public static function getDB()
{
//if the instance is not set, set it
if(is_null(self::$instance))
{
self::$instance = new Database();
self::$instance->connect();
}
return self::$instance;
}

//rest of your class below
}

This static method can be called from anywhere in any context and would allow for getting the same connected instance of the database. Just call $db = Database::getDB() anywhere you need it. For example:

function TestFunction()
{
//get an instance to the database
$dbInstance = Database::getDB();

//then use the database object like you normally would.
$dbInstance->query("SELECT * FROM `someTable`");
}

class TestClass
{
public function doSomething()
{
//get an instance to the database
$dbInstance = Database::getDB();

//then use the database object like you normally would.
$dbInstance->query("SELECT * FROM `someTable`");
}
}

$tc = new TestClass();
$tc->doSomething();

Another option, and one that I use for simplicity, is declare your connection static and reference that everywhere in your database class for queries and such. This allows for creating $db = new Database() anywhere and will just use the same connection. I've had this frowned upon as if it were same as a global because you can really only connect to one database (subsequent connections would overwrite the connection variable) But it worked for me and I didn't need multiple connections. I also like it that I can have each instance remember whatever queries were run on that instance and have a private count of the queries run.

Recommended way for passing data connection to a PHP class / method?

Passing a connection string to your classes has lots of disadvantages and no benefits. You are on the right track, but you want to pass the database object instead of a connection string.

Dependency Injection is a good way of giving your classes access to the database, which simply means to pass dependencies (ie database object) to the objects that need them, rather than the object itself obtaining the dependency from a global variable of some kind.

I would suggest that you use a method like setDb() on your classes to pass the database objects, and then store it as a property for any internal use.

For example, assuming you have created the database object $db in an initialisation script:

class SomeClass
{
protected $db;

public function setDb($db)
{
$this->db = $db;
}

public function something()
{
// do some query on the database using $this->db
}
}

$obj = new SomeClass();
$obj->setDb($db);

$obj->something();

DI gives you the benefits that you mentioned: the ability to easily switch the db without having to do lots of work in your methods. There are other benefits, namely ease of testing.

PHP : Make other functions access the $conn variable inside my database connection function

Your Desired Solution: This should work, and you'll only make one connection.

function db () {
static $conn;
if ($conn===NULL){
$conn = mysqli_connect ("localhost", "root", "", "database");
}
return $conn;
}

function someFunction () {
$conn = db();
$result = mysqli_query ($conn, "SELECT * FROM examples);
}

If you used the function someFunction($conn), that would make your code much messier, since you wouldn't actually have universal access to $conn from anywhere.

You should go with Solution B IMO. That way, you can have simple access to it Database::$conn which will be consistent throughout your script. You could should have an initialize function (you could use a different name if you want) that will initialize Database::$conn, and you can then use that to initialize other things on the Database class later, if desired.

Solution A is terrible. I did that for a long time (globalizing things), and it was a horrible idea. I should have never done that. But I did. And I learned. It just made code get progressively sloppier and sloppier.

Solution B: Database::$conn should be public if you want to be able to access it by Database::$conn from anywhere. If it's private, then you would always need to call Database::getObject();

Solution C: You're right. That would be very impractical.

Solution B rewrite:

class Database
{
/** TRUE if static variables have been initialized. FALSE otherwise
*/
private static $init = FALSE;
/** The mysqli connection object
*/
public static $conn;
/** initializes the static class variables. Only runs initialization once.
* does not return anything.
*/
public static function initialize()
{
if (self::$init===TRUE)return;
self::$init = TRUE;
self::$conn = new mysqli("localhost", "root", "", "database");
}
}

Then... call Database::initialize() at least once before it gets used.

<?php
Database::initialize();
$result = mysqli_query (Database::$conn, "SELECT * FROM examples);
?>

EDIT

  • You can also call Database::initialize() immediately after the declaration of the class, in that PHP file. Then initializing is handled.
  • I'm now far more fond of something like Database::getDb() than accessing the $conn property directly. Then initialize can be called from the getDb() function. Basically like the Desired Solution but inside a class. The class really isn't necessary, but it can be nice if you like classes, like I do.

PHP - The best way to load Database object from Model, but to have only one instance?

You are going in the wrong way about solving this.

Instead of each time manually making a new "Model" and then configuring it, you should create a structure that does it for you ( extremely simplified version ):

class ModelFactory
{
protected $connection = null;
// --- snip --

public function __construct( $connection )
{
$this->connection = $connection;
}
// --- snip --

public function buildMapper( $name )
{
$instance = new {$name}( $this->connection );
return $instance;
}
// --- snip --

}

This class you would be using in index.php or bootstrap.php , or any other file you use as entry point for your application:

// at the bootstrap level
$modelFactory = new ModelFactory( new PDO(...) );

// i am assuming that you could get $controllerName
// and $action from routing mechanism
$controller = new {$controllerName}( $modelFactory );
$controller->{$action}();

The main problem you have is actually cause by misunderstanding what Model is. In a proper MVC the Model is a layer, and not a specific class. Model layer is composed from multitude of class/instances with two major responsibilities:

  • domain business logic
  • data access and storage

The instances in first group are usually called Domain Objects or Business Objects (kinda like situation with geeks and nerds). They deal with validations, computation, different conditions, but have no clue how and where information is stored. It does not change how you make an Invoice , whether data comes from SQL, remote REST API or a screenshot of MS Word document.

Other group consists mostly of Data Mappers. They store and retrieve information from Domain Objects. This is usually where your SQL would be. But mappers do not always map directly to DB schema. In a classic many-to-many structure you might have either 1 or 2 or 3 mappers servicing the storage. Mappers usually one per each Domain Object .. but even that is not mandatory.

In a controller it would all look something like this.

public function actionFooBar()
{
$mapper = $this->modelFactory->buildMapper( 'Book' );
$book = $this->modelFactory->buildObject( 'Book' );
$patron = $this->modelFactory->buildObject( 'Patron' );

$book->setTitle('Neuromancer');
$mapper->fetch( $book );

$patron->setId( $_GET['uid']);

if ( $book->isAvailable() )
{
$book->lendTo( $user );
}

$mapper->store( $book );

}

Maybe this will give you some indications for the direction in which to take it.

Some additional video materials:

  • Advanced OO Patterns (slides)
  • Global State and Singletons
  • Don't Look For Things!

Best way to implement database connection in php

Create a connection class in a Connection.php file :-

class Connection{

public static $PDO =null;

public static function getConnectionInstance()
{
try{
$PDO = new PDO('mysql:host=localhost;dbname=keralalotteryapp','root','');
return $PDO;
}catch(PDOException $e)
{
die($e->getMessage());
}
}

}

or use this class any other php file like that :-

require_once './Connection.php';
function __construct() {
$this->dbh = Connection::getConnectionInstance();
}

create construct or call static method of connection call

Pass SQL database connection to PHP function

Your problem is fairly simple:

$connection = $Db->real_connect($servername, $username, $password, $dbname, 3306);

This is wrong. real_connect() returns a boolean marking success or failure, not a connected database object. Instead, you should send $Db into your function, and it will all work.

Pass in the connection object or create it inside class? (OOP)

I would suggest the first one, no hard coded dependency, testable and can change the connection object at anytime. I highly recommend you to watch this.



Related Topics



Leave a reply



Submit