Extending the MySQLi class - php

I want to be able to make classes which extend the MySQLi class to perform all its SQL queries.
$mysql = new mysqli('localhost', 'root', 'password', 'database') or die('error connecting to the database');
I dont know how to do this without globalising the $mysql object to use in my other methods or classes.
class Blog {
public function comment() {
global $mysql;
//rest here
}
}
Any help would be appreciated.
Thanks.

I was working on something similar. I'm happy about this singleton class that encapsulates the database login.
<?php
class db extends mysqli
{
protected static $instance;
protected static $options = array();
private function __construct() {
$o = self::$options;
// turn of error reporting
mysqli_report(MYSQLI_REPORT_OFF);
// connect to database
#parent::__construct(isset($o['host']) ? $o['host'] : 'localhost',
isset($o['user']) ? $o['user'] : 'root',
isset($o['pass']) ? $o['pass'] : '',
isset($o['dbname']) ? $o['dbname'] : 'world',
isset($o['port']) ? $o['port'] : 3306,
isset($o['sock']) ? $o['sock'] : false );
// check if a connection established
if( mysqli_connect_errno() ) {
throw new exception(mysqli_connect_error(), mysqli_connect_errno());
}
}
public static function getInstance() {
if( !self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
public static function setOptions( array $opt ) {
self::$options = array_merge(self::$options, $opt);
}
public function query($query) {
if( !$this->real_query($query) ) {
throw new exception( $this->error, $this->errno );
}
$result = new mysqli_result($this);
return $result;
}
public function prepare($query) {
$stmt = new mysqli_stmt($this, $query);
return $stmt;
}
}
To use you can have something like this:
<?php
require "db.class.php";
$sql = db::getInstance();
$result = $sql->query("select * from city");
/* Fetch the results of the query */
while( $row = $result->fetch_assoc() ){
printf("%s (%s)\n", $row['Name'], $row['Population']);
}
?>

My suggestion is to create a Singleton DataAccess class, instantiate that class in a global config file and call it in your Blog class like $query = DataAccess::query("SELECT * FROM blog WHERE id = ".$id).
Look into the Singleton pattern, it's a pretty easy to understand designpattern. Perfect for this situation.
Your DataAccess class can have several methods like query, fetchAssoc, numRows, checkUniqueValue, transactionStart, transactionCommit, transactionRollback etc etc. Those function could also be setup as an Interface which gets implemented by the DataAccess class. That way you can easily extend your DataAccess class for multiple database management systems.
The above pretty much describes my DataAccess model.

You can use PHP's extends keyword just for any other class:
class MyCustomSql extends mysqli {
public function __construct($host, $user, $password, $database) {
parent::__construct($host, $user, $password, $database);
}
public function someOtherMethod() {
}
}
$sql = new MyCustomSql('localhost', 'root', 'password', 'database') or die('Cannot connect!');
or better use object aggregation instead of inheritance:
class MySqlManipulator {
private $db;
public function __construct($host, $user, $password, $database) {
$this->db = new mysqli($host, $user, $password, $database);
}
public function someOtherMethod() {
return $this->db->query("SELECT * FROM blah_blah");
}
}
$mysqlmanipulator = new MySqlManipulator('localhost', 'root', 'password', 'database') or die('Cannot connect!');

My standard method is to make a singleton class that acts as the database accessor, and a base class that everything requiring such access inherits from.
So:
class Base {
protected $db;
function __construct(){
$this->db= MyDBSingleton::get_link();
//any other "global" vars you might want
}
}
class myClass extends Base {
function __construct($var) {
parent::__construct();// runs Base constructor
$this->init($var);
}
function init($id) {
$id=(int) $id;
$this->db->query("SELECT * FROM mytable WHERE id=$id");
//etc.
}
}

Have a look at PDO, which throw exceptions for you to catch if a query fails. It's widely used and tested so you shouldn't have a problem finding existing solutions whilst using it.
To inject it into your blog class:
class Blog {
private $_db;
public function __construct(PDO $db) {
$this->_db = $db
}
public function comment() {
return $this->_db->query(/*something*/);
}
}

Related

how i can prevent multiple time connected to database

here is my code
pdo.php
class Connection {
public function __construct() {
$this->connect ($db);
}
private function connect($db) {
try {
if (! $db){
$this->db = new PDO ( 'mysql:host=localhost;dbname=Shopping;charset=utf8', 'xxxx', 'xxxxx' );
echo 'Connected';
return $this->db;
}
catch ( PDOException $conError ) {
echo 'failed to connect DB' . $conError->getMessage ();
}
}
}
product.php
class ProductInsert extends Connection { //here my function is called multiple times
function __construct() {
parent::__construct($db);
}
public function prdInsert(.....)
{ ........}
here my problem is database connection is opened multiple time. when ever i am calling the productInsert() then database connection is opened how i can prevent this
Do not extend your application class from database class.
This is your main problem.
They are too different classes having nothing in common.
So you have to just use your db object as a property.
Connection class is also useless at the moment, as it's just a leaky disguise for the PDO.
So, just create raw PDO object and then pass it in the constructor of product
class ProductInsert
{
function __construct(PDO $db)
{
$this->db = $db;
}
public function prdInsert(.....)
}
And for goodness sake, learn to indent your code.
class Connection {
public function __construct($db) {
return $this->connect($db);
}
private function connect($db) {
try {
if (! $db){
$db = new PDO ( 'mysql:host=localhost;dbname=Shopping;charset=utf8', 'xxxx', 'xxxxx' );
echo 'new connection';
}
return $db;
}
catch ( PDOException $conError ) {
echo 'failed to connect DB' . $conError->getMessage ();
}
}
}
here is the solution
pdo.php
class Connection {
// Declare instance
private static $instance = NULL;
// the constructor is set to private so so nobody can create a new instance using new
private function __construct() {
// maybe set the db name here later
}
// Return DB instance or create intitial connection #return object (PDO) #access public
public static function getInstance() {
if (! self::$instance) {
self::$instance = new PDO ( 'mysql:host=localhost;dbname=Shopping;charset=utf8', 'root', 'vss0ftech' );
self::$instance->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
echo 'connected';
} else
echo 'connection is already existed';
return self::$instance;
}
// Like the constructor, we make __clone private so nobody can clone the instance
PRIVATE FUNCTION __CLONE() {
}
}
product.php
here we can call the method as like this
class ProductInsert {
public function prdInsert(.....) {
$result_By_Vendor_And_Title = Connection::getInstance ()->query ( "select * from........)
}
}

Creating a globally accessible MySQLi object

I have multiple classes that use static methods. These functions connect to the database using
$mysqli = new mysqli(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
where the constants DB_SERVER, DB_USER, DB_PASS, DB_NAME are database variables defined in a globally accessible file. Recently, my site started becoming slow and after profiling the script I realized that the call to create the object($mysqli) was causing this problem.
Most of my classes extend from mysqli such that
public function __construct($user_id) {
parent::__construct(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
$this->retrieve_user_details($user_id);
$this->check_user_account_type();
}
It is to my understanding that static methods DO NOT use the __construct method.
Could someone guide me on how I can create the $mysqli object once such that it can be accessed by all static methods that require it.
Here is one approach:
Create a singleton class, that can be accessed statically from anywhere.
class DBConnector {
private static $instance ;
public function __construct($host, $user, $password, $db){
if (self::$instance){
exit("Instance on DBConnection already exists.") ;
}
}
public static function getInstance(){
if (!self::$instance){
self::$instance = new DBConnector(a,b,c,d) ;
}
return $instance ;
}
}
An example would be:
$mysqli = DBConnector::getInstance() ;
Hovewer I suggest using another solution as well:
$mysqli = new MySQLi(a,b,c,d) ;
Then you could pass that object to other classes (constructor)
class Shop {
private $mysqli ;
public function __construct(MySQLi $mysqli){
$this->mysqli = $mysqli ;
}
}
$show = new Shop($mysqli) ;
To elaborate on a mysqli singleton:
define('SERVER', 'localhost');
define('USERNAME', 'root');
define('PASSWORD', 'password');
define('DATABASE', 'databaseName');
class mysqliSingleton
{
private static $instance;
private $connection;
private function __construct()
{
$this->connection = new mysqli(SERVER,USERNAME,PASSWORD,DATABASE);
}
public static function init()
{
if(is_null(self::$instance))
{
self::$instance = new mysqliSingleton();
}
return self::$instance;
}
public function __call($name, $args)
{
if(method_exists($this->connection, $name))
{
return call_user_func_array(array($this->connection, $name), $args);
} else {
trigger_error('Unknown Method ' . $name . '()', E_USER_WARNING);
return false;
}
}
}
You can then request the database connection by calling:
$db = mysqliSingleton::init();
You can then retrieve the database connection in your own objects:
class yourClass
{
protected $db;
public function __construct()
{
$this->db = mysqliSingleton::init();
}
}
This is the shortest version I could come up with for Bootstrap 3.
$(document).ready(function() {
if (hash = window.location.hash) {
$('.nav-tabs a[href="' + hash + '"]').tab('show');
}
});

PHP OOP declaring class into class

I have 2 classes and I would like to have 1 more for comfort :)
So I have class for database and system. I would like to have 3rd classs for functions. This class MUST use functions from database since there are SQL Queries. This is What I ended with:
class database {
public function __construct() {
$this->mysqli = new mysqli('localhost', 'root', '', 'roids');
$this->func = new functions();
}
}
class functions {
function __construct(){
$db = new database();
}
public function banned() {
$q = $db->select($this->prefix."banned", "*", "banned_ip", $this->getIP());
if (0 == 0) {
header('Location: banned.php'); // For testing
}
}
}
And I this kind of version ends in cycle. Any solutions ? Thanks a lot
Some of your classes must be a source, so other classes may use instances of it.
Let me show you one example:
class DataBase { //THIS class is a source.
public $mysqli ;
public function __construct(){
$this->mysqli = new mysqli('localhost', 'root', '', 'roids');
$this->mysqli->set_charset("utf-8") ;
}
public function ready(){
return ($this->mysqli instanceof MySQLi && $this->mysqli->ping()) ;
}
}
class User {
protected $db;
public function __construct(DataBase $db){
$this->db = $db ; //Now you can use your source
}
public function isBanned(){
if ($this->db->ready()){
$result = $this->db->mysqli->query("SELECT id FROM banned WHERE name='Hacker' ; ") ;
return ($result && $result->num_rows >= 1) ;
}
return false ;
}
}
Then instantiate the source and give it to instance of User:
$database = new DataBase() ;
$user = new User($database) ;
Now you can use a more complexed function:
if ($user->isBanned()) exit("You are banned") ;
The same way you can make class Functions and use it (other classes may use it) as a source.

Extending mysqli and using multiple classes

I'm new to PHP oop stuff.
I'm trying to create class database and call other classes from it. Am I doing it the right way?
class database:
class database extends mysqli {
private $classes = array();
public function __construct() {
parent::__construct('localhost', 'root', 'password', 'database');
if (mysqli_connect_error()) {
$this->error(mysqli_connect_errno(), mysqli_connect_error());
}
}
public function __call($class, $args) {
if (!isset($this->classes[$class])) {
$class = 'db_'.$class;
$this->classes[$class] = new $class();
}
return $this->classes[$class];
}
private function error($eNo, $eMsg) {
die ('MySQL error: ('.$eNo.': '.$eMsg);
}
}
class db_users:
class db_users extends database {
public function test() {
echo 'foo';
}
}
and how I'm using it
$db = new database();
$db->users()->test();
Is it the right way or should it be done another way?
Thank you.
You can do it that way, there's nothing wrong with that (I do something similar quite often). The only thing I would suggest is using exceptions instead of die (that way you can safely handle the error)...
protected function error($eNo, $eMsg, $extra = '') {
throw new Exception('MySQL error: ['.$eNo.'] '.$eMsg.': '.$extra);
}
Plus, I'd suggest overloading the query method as well
public function query($sql, $result_mode = MYSQLI_STORE_RESULT) {
$result = parent::query($sql, $result_mode);
if ($result === false) {
$this->error($this->errno, $this->errstr, $sql);
}
return $result;
}
I'd also suggest storing a copy of the $db object inside of the child class. So:
class db_users extends database {
protected $db = null;
public function __construct(Database $db) {
$this->db = $db;
}
public function test() {
echo 'foo';
}
}
Then, in __call:
if (!isset($this->classes[$class])) {
$class = 'db_'.$class;
$this->classes[$class] = new $class($this);
}
There is nothing wrong with this factory style for creating classes. I'd place a bit of exception handling in it.
My only other concern is extending database in your sub classes.
So I'd modify as follows:
public function __call($className, $args) {
if (!isset($this->classes[$class])) {
if(include_once('db_'.$class)) {
$class = 'db_'.$class;
$this->classes[$class] = new $class($this);
} else {
throw new Exception("Db class not found");
}
}
return $this->classes[$class];
}
And the users class as:
public class db_users {
private $db;
public __constructor($db) {
$this->db = $db;
}
public function test() {
return 'Foo';
}
}

Any simpler / better way of making a mysql singleton db class in php?

Here's the one I'm using:
<?php
final class Database {
private static $oDb;
public static function init() {
if(self::$oDb == NULL)
{
self::$oDb = mysql_connect('localhost', 'mysql_user', 'mysql_password') or die(mysql_error());
mysql_select_db('mysql_db_name', self::$oDb) or die (mysql_error());;
}
return self::$oDb;
}
public function query($sql)
{
return mysql_query($sql) or die(mysql_error());
}
}
?>
Usage:
$oDb = Database::init();
$sql = foo;
$oDb->query($sql);
Assuming that I only want it to connect and execute this one query function, are there any improvements I should make on the class? Memory or efficiency of code?
Also, is there an efficient way I can get the db credentials from a config file? I know I can't use includes inside my class.
I usually use lazy initialization for this sort of situation and only have one public method (in this case), with a private constructor to prevent outside instantiation (per the Singleton pattern):
class Database {
private static $instance;
private $conn;
private function Database() {
// do init stuff
require_once('dbconfig.php'); // contains define('DB_USER', 'webuser'); etc...
$this->conn = mysql_connect(DB_HOST, DB_USER, DB_PASS); // do error checking
}
public static function getInstance() {
if(!self::$instance) {
self::$instance = new Database();
}
return self::$instance;
}
public static function query($sql) {
$instance = self::getInstance();
return mysql_query($sql, $instance->conn);
}
}
Then you can just call $dbHandle = Database::getInstance() anytime you need to use it. Or in this case since a static query method is defined, you can use Database::query("select * from xx;"); without having to call any sort of init at all.
That's a simple as it gets, that will work fine.
You can pass your credentials to init();
include(config.php);
$oDb = Database::init( DB_HOST, DB_NAME, DB_USER, DB_PASSWORD );
$sql = foo;
$oDb->query($sql);
You can use an include inside a function inside a class
<?php
final class Database {
private static $oDb;
public static function init() {
if(self::$oDb == NULL)
{
include('config.php')
self::$oDb = mysql_connect(DB_HOST, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_NAME, self::$oDb) or die (mysql_error());;
}
return self::$oDb;
}
public function query($sql)
{
return mysql_query($sql) or die(mysql_error());
}
}
?>
or you can just pass the variables...
<?php
final class Database {
private static $oDb;
public static function init($host, $user, $pass, $name) {
if(self::$oDb == NULL)
{
self::$oDb = mysql_connect($host,$user,$pass) or die(mysql_error());
mysql_select_db($name, self::$oDb) or die (mysql_error());;
}
return self::$oDb;
}
public function query($sql)
{
return mysql_query($sql) or die(mysql_error());
}
}
?>
or you can store the credentials in a php.ini file
<?php
final class Database {
private static $oDb;
public static function init($db_name) {
if(self::$oDb == NULL)
{
self::$oDb = mysql_connect() or die(mysql_error());
mysql_select_db($db_name, self::$oDb) or die (mysql_error());;
}
return self::$oDb;
}
public function query($sql)
{
return mysql_query($sql) or die(mysql_error());
}
}
?>
php.ini file:
mysql.default_host="host"
mysql.default_user="user"
mysql.default_password="password"
For singleton classes, the model that Dan Breen followed is cleanest and very common. However, in this case, I would also allow the getInstance method to accept some parameters so that you can override your default configuration at instantiation time, or just get a reference without creating a connection (both use-cases happen from time to time).
Database.php
require_once("../path/to/config/database.php");
class Database {
private static $instances = array();
private function Database($host, $user, $password, $name) {
// do init stuff
}
public static getInstance(
$host=DB_HOST, $user=DB_USER, $password=DB_PASSWORD, $name=DB_NAME
) {
$key = strtolower($host . $user . $password . $name);
if ( !$self::instances[$key] ) {
$self::instances[$key] = new Database($host, $user, $password, $name);
}
return $self::instances[$key];
}
}
..config/database.php:
define("DB_HOST", "localhost");
define("DB_USER", "mrsqlguy");
define("DB_PASS", "!!!");
define("DB_NAME", "just_another_wordpress");
Edit: I've changed it to act more like a flyweight to ensure that you only get one instance for each connect location/database. This addresses your concerns and maintains a degree of flexibility.

Categories