PHP: use a database within a class - php

I already have a database file that connects to a database when I include it
class-database.php
class dbFactory {
private static $host = 'some.host.com';
private static $name = 'someDB';
private static $user = 'someUser';
private static $pass = 'somePassword';
public function __construct() { }
public static function pdo() {
try {
# MySQL with PDO_MYSQL
return new PDO("mysql:host=$host;dbname=$name", $user, $pass);
}
catch(PDOException $e) {
echo $e->getMessage();
return null;
exit;
}
} // End: pdo()
} //End class
I usually access this by:
require( 'some-file-path' . 'class-database.php' );
$db = dbFactory::pdo();
Here is the question:
How can I access $db from within another class?
For instance, if I have a class file called class-html.php and within that class (AKA, as part of the class code) I need something like...:
class-html.php
class html {
...some code...
$db->query('SELECT * FROM tbl_head');
...some more code...
} //End: html
What I've been doing without success is:
require( 'some-file-path' . 'class-database.php' );
$db = dbFactory::pdo();
require( 'some-file-path' . 'class-html.php' );
I am getting error messages and am not sure what to do from here

You can use a Singleton class
class dbFactory {
//...
private static $pdo_instance = null;
private static function getPDOinstance() {
if (self::$pdo_instance === null) {
try {
self::$pdo_instance = new PDO("...");
} catch (PDOException $e) {
//...
}
}
return self::$pdo_instance;
}
}
When you now access dbFactory::getPDOinstance() you'll only have one PDO instance of creating new ones inside each class using the DB

Your class inside class-html.php can be modified a bit, along the following lines:
require( 'some-file-path' . 'class-database.php' );
class SomeClass {
public $db;
def __construct() {
$db = dbFactory::getPDOinstance();
// existing code ..
}
// other code
}
Then, you can require the class as usual and:
require( 'some-file-path' . 'class-html.php' );
$obj = new SomeClass();
$obj->db->query('SELECT * FROM tbl_head')
UPDATE: This will create a new PDO instance if you instantiate SomeClass more than once.
UPDATE: Made use of kingkero's answer to use existing dbFactory instance, instead.

Related

Undefined Variable in Derivative Class with Private Variable in PHP?

I'm attempting to create a mysql query using OOP in PHP. In the code below the class "database_disconnection" does not toss any errors or notices, however the last class "database_query" gives me a notice that $database_handle is undefined. I have no idea what's causing this as I created the database_query class as a derivative class of database_connection, which include the $database_handle variable as private. Any help would be greatly appreciated!
Instantiating the objects:
include("includes/database_classes.php");
new database_connection;
new database_query('SELECT * FROM users');
and the classes:
<?php
/*----------------------------------------------------------------------------------------------------*/
class database_connection
{
private $username = 'root';
private $password = '';
private $hostname = 'localhost';
private $database = 'assistant';
private $database_handle;
function connect()
{
try
{
$database_handle = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
}
catch (PDOException $e)
{
print "Error!: " . $e ->getMessage() . "<br/>";
die();
}
}
}
/*----------------------------------------------------------------------------------------------------*/
class database_disconnection extends database_connection
{
function disconnect()
{
$database_handle = null;
}
}
/*----------------------------------------------------------------------------------------------------*/
class database_query extends database_connection
{
private $mysql_statement;
function __construct( $mysql_statement )
{
$this->mysql_statement = $mysql_statement;
foreach($database_handle->query("$mysql_statement") as $row) {
print_r($row);
}
}
}
/*----------------------------------------------------------------------------------------------------*/
?>
In your database_query constructor, you're attempting to use $database_handle before initializing it. If you notice, you only initialize in the connect function of your parent class (database_connection).
Either call connect before trying to refer to it, or initialize it in the parent's constructor, and call it (parent::__construct();).

Return database connection from function

I'm trying to return $db connection from function, so that I could use it in another function. But someone functions don't understand $db variable.
function dbConnection(){
$dbhost = 'localhost';
$dbuser = '...';
$dbpass = '...';
$dbname = '...';
try {
$db = new PDO("mysql:host=$dbhost;dbname=$dbname;charset=UTF8", $dbuser, $dbpass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $db;
} catch (PDOException $e){
echo 'Connection failed: ' . $e->getMessage();
}
}
Then use it in all of my functions.
function getCurrentFile(){
dbConnection();
$stmt = $db->prepare(...);
$stmt->execute();
}
Are there more preferable way to handle db connections? I used to require_once config.php(where is only db connection) file every time, but I don't want to do it anymore.
One of the options is define singletone class providing database object:
// File: DbConection.php
class DbConnection
{
/**
* #var \PDO
*/
private static $pdo;
private function __constructor()
{
}
public static function getInstance()
{
if(null === self::$pdo) {
self::$pdo = new \PDO('....);
}
return $self::pdo;
}
private function __clone()
{
}
private function __wakeup()
{
}
}
If you are using composer tool, add this line to composer.json file:
"autoload": {
"classmap": [
"path_to_your_file/DbConnection.php"
]
},
In your project, on bootstrap include generated by composer vendor/autoload.php file and start using class by:
use DbConnection;
DbConnection::getInstance();
in whole projec.
Write down your db connection code in class and create object to use everywhere else in your system.

Call to a member function on a non-object

I am new to php oop , so struggling a bit .
i have a database connection class viz :
class config{
protected $HOST = "localhost";
protected $USERNAME = "something" ;
protected $PASSWORD = "something";
protected $DATABASE = "something";
// Constructor - open DB connection
function __construct() {
try {
$this->db = new mysqli($this->HOST, $this->USERNAME, $this->PASSWORD, $this-
>DATABASE);
$this->db->autocommit(FALSE);
}
catch(Exception $e)
{
if($this->db->connect_errno > 0){
echo 'Caught exception: ', $e->getMessage(), "\n";
}
}
}
// Destructor - close DB connection
function __destruct() {
$this->db->close();
}
}
$api = new Config();
Now i have another class from which i need to perform some tasks ...but i get FATAL error .
second class :
class Myclass extends config {
function __construct(){}
public function myfunction()
{
try{
$stmt = $this->db->stmt_init(); /* Error here : Fatal error: Call to a member
function stmt_init() on a non-object */
$query = "SELECT ABC FROM table " ;
$stmt = $this->db->prepare($query); /* Error here : Fatal error: Call to a member
function prepare() on a non-object */
}
catch(){}
}
}
Please guide me with proper remedial code snippet
In your child class, you need to call the parent constructor. PHP won't automatically call parent constructor's when a child class is instantiated.
class Myclass extends config {
function __construct($h, $u, $p, $d){ parent::__construct($h, $u, $p, $d); }
Also, you don't have a $db property in the parent class, so add that
class config{
protected $db;
protected $HOST = "localhost";
protected $USERNAME = "something" ;
protected $PASSWORD = "something";
protected $DATABASE = "something";
Edit: Dependency Injection approach:
class config{
public $HOST = "localhost";
public $USERNAME = "something" ;
public $PASSWORD = "something";
public $DATABASE = "something";
}
class Myclass
{
protected $db;
function __construct($db)
{
$this->db = $db;
}
public function myfunction()
{
// do whatever with $this->db
}
}
$config = new Config();
try
{
$db = new mysqli($config->HOST, $config->USERNAME, $config->PASSWORD, $config->DATABASE);
$db->autocommit(FALSE);
}
catch(Exception $e)
{
if($db->connect_errno > 0){
echo 'Caught exception: ', $e->getMessage(), "\n";
}
}
$myclass = new Myclass($db);
Have a look into Dependency Injection. This is a favorable approach for dealing with classes that need access to a database. Instead of having all your classes extend the database, just pass the datsbase object as a parameter when creating new classes (that need the db).
Your derived class constructor is not calling the base constructor, so $this->db does not have the value it's supposed to. In PHP you must do this explicitly.
In this particular case, you should remove the derived constructor altogether since it's not doing anything. This will let PHP use the base constructor directly.

PHP - multiple different databases dependency injected class

I've spent the last several hours trying to find an answer to the "best", most logical, etc way to write a php database class to simultaneously connect to one postgresql db and one mysql db. Also, I'd like to adopt a Dependency Injection design but am new to that whole concept.
So far I've come up with...
class Database {
public function PgSqlConnect() {
/* Connect to database */
$host = 'localhost';
$dbname = '---';
$user = '---';
$pass = '---';
$timeout = 5; /* seconds */
try {
$pgsql_dbh = new PDO("pgsql:host=$host; dbname=$dbname", $user, $pass);
$pgsql_dbh->setAttribute( PDO::ATTR_TIMEOUT, $timeout );
$pgsql_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $pgsql_dbh;
} catch( PDOException $e ) {
echo 'Unable to connect to database: ' . $e->getMessage();
}
}
public function MySqlConnect() {
/* Connect to database */
$host = 'localhost';
$dbname = '---';
$user = '---';
$pass = '---';
$timeout = 5; /* seconds */
try {
$mysql_dbh = new PDO("mysql:host=$host; dbname=$dbname", $user, $pass);
$mysql_dbh->setAttribute( PDO::ATTR_TIMEOUT, $timeout );
$mysql_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $mysql_dbh;
} catch( PDOException $e ) {
echo 'Unable to connect to database: ' . $e->getMessage();
}
}
}
Obviously the duplicated code violates the DRY approach. I know and have seen many examples of multiple db connections, but most deal with same driver and don't provide DI capability.
I should also add that I've considered placing the connection details into the Database class constructor as...
$driver = 'mysql';
...
$mysqldb = new Database($driver,$un,$pw,...);
$driver = 'pgsql';
...
$pgsqldb = new Database($driver,$un,$pw,...);
but I don't know if that is really a good idea nor how well it would work with DI.
Many thanks!
You should create an interface first for all the DB operations.
interface IDatabase
{
function connect();
function query();
...
}
Then have different driver classes implementing this interface
class MySQLDB implements IDatabase
{
}
class PGSQLDB implements IDatabase
{
}
This way you can easily use dependency injection.
class Test
{
private $db;
function __construct(IDatabase $db)
{
$this->db = $db;
}
}
You can call it as:
$mysqldb = new MySQLDB();
$test = new Test($mysqldb);
or
$pgsqldb = new PGSQLDB();
$test = new Test($pgsqldb);
To avoid duplicated code you can extend an abstract class
abstract class AbstractDb {
public function connect() {
// common code to avoid duplication
echo 'connected!';
}
abstract public function escapeField();
abstract public function escapeValue();
}
class MySQL extends AbstractDb {
public function escapeField() {
// Db-specific method
}
public function escapeValue() {
// Db-specific method
}
}
$db = new MySQL;
$db->connect();
Or use composition, and let the Db class use a different driver for db-specific methods
interface IDriver {
public function escapeField();
public function escapeValue();
}
class MySQLDriver implements IDriver {
public function escapeField() {
// Db-specific method
}
public function escapeValue() {
// Db-specific method
}
}
class Db {
public function __construct($driver) {
$this->driver = $driver;
}
public function connect() {
// common code here ? idk, it's just an example
echo 'connect!';
}
// this method is db-specific, so we call the driver
public function escapeField($field) {
return $this->driver->escapeField($field);
}
public function escapeValue() {
// same here
}
}
$db = new Db(new MySQLDriver);
$db->connect();
In php 5.4 there will be traits, so there will be more approaches to avoid code duplication.

php classes - how would one go about loading a "module" object within an existing object only when its needed?

Ok so i have the following code setup which seems to work fine:
user handler "module":
class user_handler
{
private $dbo;
public function __construct($dbo)
{
$this->dbo = $dbo;
}
public function user_table_method()
{
$this->dbo->generic_db_method();
}
}
the connection class:
class connection
{
private $dbc;
public $user;
public function __construct()
{
$this->dbc = 'connection';
$this->user = new user_handler($this);
}
public function generic_db_method()
{
echo '<p>doing stuff with ' . $this->dbc . '</p>';
}
}
Then i can access user handler methods like so:
$dbc = new connection();
$dbc->user->user_table_method();
My question is this:
Would it be possible with a method in the connection class to create the _user object only when it's required?
What i'm thinking of is a method that would be used like so:
$dbc->add_handle('user', 'user_handler');
Which would create a new public property called user from scratch and set it as a new
user_handler object:
// in more detail
public function add_handle($name, $module)
{
if(!isset($this->/*somehow use $name*/))
{
$this->/*somehow use $name*/ = new /*somehow use $module*/();
}
}
..so the new way to set it up would be like:
$dbc = new connection();
$dbc->add_handle('user', 'user_handler');
$dbc->user->user_table_method();
Thanks in advance! (looking at php 5.2 and up)
public function add_handle($name, $module)
{
if(!isset($this->$name))
{
$this->$name = new $module();
}
}
Then you would just do similar to how you were thinking:
$dbc = new connection();
$name = 'user';
$module = 'somemodule';
$dbc->add_handle($name, $module);
$dbc->user->user_table_method();
I've also renamed it from $_user to $user as I mentioned in the comment since it is public.

Categories