I want create a global connection, so in the entire script I can access to a single object. Actually I made this class:
<?php
class Database {
private static $db;
private $connection;
private function __construct($conn) {
$this->connection = $conn;
$this->init();
}
private function init(){
// here the connection is going to execute
$host = $this->_connection['host'];
//etc...
}
function __destruct() {
$this->connection->close();
}
public static function getConnection($conn) {
if (self::$db == null) {
self::$db = new Database($conn);
}
return self::$db->connection;
}
}
?>
I pass the details of connection like this: $db = Database::getConnection($connection); Now $connection contains an array with the credentials access. Here no problem all working good. The main problem is that $db = Database::getConnection($connection); is called only when the index create the instance of the connection. My goal is call the $connection object in any models or controller, example:
class Model
{
function __construct()
{
$this->db = Database::getConnection();
}
}
how you can see I can't pass the connection parameter 'cause I want just use the connection previously established by the index.php call. How I can access to this connection without pass parameter?
You need to both make the $conn parameter optional and make sure it is passed on the first call:
public static function getConnection($conn=null) {
if (self::$db == null) {
if ($conn === null) {
throw new Exception('Can not initialize the database');
}
self::$db = new Database($conn);
}
return self::$db->connection;
}
Then you need to call the getConnection somewhere during the application start and pass the configuration to it.
After that you can use it without parameters.
If, by mistake, you don't configure the database, you'll have a clear error.
You could try this
public static function getConnection($conn = null) {
if (self::$db != null) {
return self::$db->connection;
}
//maybe add some validation here to ensure that the $conn value has been set
self::$db = new Database($conn);
return self::$db->connection;
}
or this works as well although it will throw an error if you don't set the $conn on the first call.
public static function getConnection($conn = null) {
if (self::$db == null && $conn) {
self::$db = new Database($conn);
}
return self::$db->connection;
}
It changes your logic a bit but should now work as you expect it to.
If the $conn is not supplied then it wont throw an error.
Related
I have these two code to use to connect to mongodb.
First i used this code but this doesn't seem to work.I dont know why.
class DbConnection
{
static $db = NULL;
static function getMongoCon()
{
if (self::$db === null)
{
try {
$m = new Mongo("mongodb://username:password#localhost:27017");
} catch (MongoConnectionException $e) {
die('Failed to connect to MongoDB '.$e->getMessage());
}
self::$db = $m;
}
else
{
return self::$db;
}
}
}
After this i used this way to connect mongo in another class
$db=DbConnection::getMongoCon();
$database=$db->databasename;
$collection=$db->users;
But this doesn't seem to work always . i always get error $db not defined or some other undefined error.
Second Code is this . which i used to connect to mongodb without having to create multiple connection. This works fine without having problem.
class DbConnection{
static protected $_instance;
protected $db = null;
final protected function __construct() {
$m = new Mongo("mongodb://username:password#localhost:27017");
$this->db = $m->selectDB( "databasename" );
}
static public function getInstance() {
if (!(self::$_instance instanceof self)) {
self::$_instance = new self();
}
return self::$_instance;
}
public function getConnection() {
return $this->db;
}
final protected function __clone() { }
}
To use this code in another class i used
$db=DbConnection::getInstance()->getConnection();
$collection=$db->users;
I dont know why second one worked but not the first code. if i use both in mysql both works fine.
Also can this be issue than in second code i have create connection to mongodatabase and kept it open and directly used in another class.
please describe simply why the second code worked fine and first didn't worked.
In the first piece of code, when the $db variable is null and you create a new connection, your getMongoCon function doesn't return anything, hence when you try to use it on the example, $db=DbConnection::getMongoCon(); end ups asigning null to the $db variable.
To make it work correctly, you should do something like this:
...
static function getMongoCon()
{
if (self::$db === null)
{
try {
$m = new Mongo("mongodb://username:password#localhost:27017");
} catch (MongoConnectionException $e) {
die('Failed to connect to MongoDB '.$e->getMessage());
}
self::$db = $m;
}
return self::$db;
}
...
I have the following, however I'm unable to access the database functions outside of the initial db class?
Thanks!
database.php
class db
{
private $connection;
public function __construct()
{
$this->connection = new PDO();
}
}
admin.php
class admin
{
private $connection
public function __construct(db $connection)
{
$this->connection = $connection;
}
function myFunc()
{
// How do I access the connection here?
}
}
main.php
//include db.php
//include admin.php
$connection = new db();
$admin = new admin($connection);
// How do I access the DB here?
First of all, why are you encapsulating PDO just to class containing that one object? Cannot you use PDO directly?
One of the common practices would be to implement getter in db class, like:
class db {
...
public function getPDO(){
return $this->connection;
}
}
Another way is to re-implement every function (why would you do that?!), or use __call magic function...
Or just make $connection public ;)
Or you could extend PDO class (I'm not sure whether it'll work):
class DB extends PDO {
public function __construct ( $dsn, $username = null, $password = null, $driver_options = array()){
parent::__construct( $dsn, $username, $password, $driver_options);
... more of your stuff
}
public function myFunc(){
$this->...
}
}
ok, you really need to go and read up on object-oriented design, and access modifiers. I'll explain what you need to do here, but this is a band-aid solution, and you need to deeply understand how things are working here.
In your admin class, you defined the connection as a private attribute of the class. So in the myFunc function, you simply do $this->connection to access the connection that you created in the constructor.
In your main.php file, the object you are getting rom initializing a DB object is not the connection. It is the db object as a whole, so you can not pass the connection by itself to the admin class (it is defined as private, so nobody outside the class can view it). However, why do you need to pass it to the admin class? Managing the DB connection should be the responsibility of the DB class.
In other words, what are you trying to achieve by exposing the DB connection to the admin class?
Upate: based on the reply here is a suggested answer:
class Database {
private $connection;
public function __construct() {
$this->connection = new PDO();
}
}
class Admin {
private $db;
public function __construct() {
$this->db = new Database();
}
public function myFunc() {
$this->db->query('...');
}
}
In your main.php file:
$admin = new Admin();
$admin->myFunc();
Keep in mind, every admin object is going to create a new connection to the DB, so if you create many admin objects you might face some issues. You can get around this by declaring the DB to be a singleton.
How about this:Updated
<pre>
<?php
class DB {
private $host;
private $user;
private $pass;
private $dbase;
private $connection;
public function __construct($host,$user,$pass,$dbase)
{
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->dbase = $dbase;
$this->connection = new PDO("mysql:host=$this->host;dbname=$this->dbase", $this->user, $this->pass);
}
public function connect()
{
return $this->connection;
}
public function close()
{
unset($this->connection);
return true;
}
}
$dbh = new DB('localhost','root','','inventory');
$result = $dbh->connect()->query("SELECT * FROM products")->fetchAll(PDO::FETCH_ASSOC);
print_r($result);
?>
</pre>
Updated with files separation
database.php
class db
{
private $connection;
public function __construct()
{
$this->connection = new PDO();
}
}
admin.php
class admin
{
private $connection
public function __construct(db $connection)
{
$this->connection = $connection;
}
function myFunc()
{
return $this->connection->prepare('SQL');
}
function getConnection()
{
return $this->connection;
}
}
main.php
require_once 'database.php';
require_once 'admin.php';
$connection = new db();
$admin = new admin($connection);
$admin->myFunc()->execute();
I am trying to write a db util class using the singleton pattern. My problem is that the "connection" object is always null. The connection settings are correct. What could i be doing wrong ? Also, i am relatively new to php development. What method should i use to figure out what's wrong ? Code follows.
class DBUtil {
public $connection = NULL; //mysqli_connection object
private static $instance = NULL;
private function _constructor($conn){
//$this->connection = mysqli_connect(TagMetroConfiguration::getConfigurationValueFor("db_servser_name"), TagMetroConfiguration::getConfigurationValueFor("db_username"), TagMetroConfiguration::getConfigurationValueFor("db_password"), TagMetroConfiguration::getConfigurationValueFor("db_name"));
$this->connection = new mysqli("localhost", "root", "toor", "testdb");
}
public static function getInstance(){
if(DBUtil::$instance == NULL){
try{
DBUtil::$instance = new DBUtil();
}catch(Exception $ex){
throw new Exception("Unable to create DB Instance");
}
}
return DBUtil::$instance;
}
}
Your constructor function should be named __construct (notice two underscores).
Also, in your constructor, you have one parameter, $conn. When you call new DBUtil(), you are not providing that input parameter, so perhaps it's calling the default contructor, not your custom one.
If you want the input parameter $conn to be optional, try __construct($conn = null).
Or try calling it as new DBUtil(null).
private function _constructor($conn) ??
should this be
private function __construct($conn)
There should be two underscores __ (__construct).
You should do like this :
class DBUtil {
private static $instance;
private function _construct(){
$this->$instance = new mysqli("localhost", "root", "toor", "testdb");
}
public static function getInstance(){
if(!isset(self::$instance){
try{
self::$instance = new DBUtil();
}catch(Exception $ex){
throw new Exception("Unable to create DB Instance");
}
}
return self::$instance;
}
In PHP, I have following Singleton Database Class:
class Database
{
private static $instance;
private function __construct()
{
self::$instance = new mysqli('localhost', 'root', 'Matthias', 'financecontrol', '3307');
if (!self::$instance) {
throw new Exception('Could not connect to database in function __construct.');
}
}
public static function getInstance()
{
if (!self::$instance) {
self::$instance = new Database();
}
return self::$instance;
}
}
Whenever I try to perform a query on the database in another PHP file, for example to check whether a user already exists:
function userExists($username)
{
try {
$connection = Database::getInstance();
$result = $connection->query("select * from user where username='$username'");
if (!$result) {
throw new Exception("Connection to database failed in function userExists.");
}
if ($result->num_rows > 0) {
return true;
} else {
return false;
}
} catch (Exception $ex) {
$errorPager = new ErrorpageGenerator();
$errorPager->generateErrorPage($ex->getMessage());
return false;
}
}
I get an error message "PHP Fatal error: Call to undefined method Database::query() in User.php on line 44"
I've tried adding a query function in the Database class, but that did not seem to fix the problem. Any ideas? Thanks
You have to add this method of course. But you cannot assign Database() and the mySQLi object to m_pInstance
so do:
class Database
{
private static $conn;
// ...
public function __construct()
{
self::$conn = new mysqli('localhost', 'root', 'root', 'database', '3307');
//...
and then
public function query($sql)
{
return self::$conn->query($sql);
// or
return mysqli_query(self::$conn, $sql);
}
EDIT
Working code:
class Database
{
private static $instance = null;
private static $conn;
private function __construct()
{
self::$conn = new mysqli('localhost', 'root', 'root', 'database', '3307');
}
public static function getInstance()
{
if (self::$instance == null) {
self::$instance = new Database();
}
return self::$instance;
}
public function query($sql)
{
return self::$conn->query($sql);
}
}
You get this error, because Database::$m_pInstance is contains an instance of Database class and not instance of MySQLi. You have created a "conflict" between to parts of the code:
public static function getInstance()
{
if (!self::$m_pInstance) {
self::$m_pInstance = new Database(); // << PROBLEM
}
return self::$m_pInstance;
}
Which overrides what your constructor does:
private function __construct()
{
self::$m_pInstance = new mysqli( /* .. */ ); // PROBLEM
if (!self::$m_pInstance) {
throw new Exception('Could not .. blah');
}
else {
return self::$m_pInstance;
}
}
Even though the constructor assigns self::$m_pInstance the instance of MySQLi object, it gets overridden by self::$instance = new Database(); right after.
Also, in php __constuct() method should not return, ever.
That said, i think is should warn you that singleton is considered to be an anti-patterns, and should be avoided. Your code also has the unintended side-effect, forcing you to have only one database (not connection, the database) available per application.
You might benefit from watching few lectures:
Advanced OO Patterns (slides)
Global State and Singletons
Don't Look For Things!
Your code does not look right.
first, you assign $m_pInstance a new Database instance. But then, in the constructor, you assign it a new mysqli instance. I am unsure how php handles this case, but it seems that it treats it as Database object as indicated by your error message. The Database class however does not have a query method.
So the solution would be to save the mysqli object in a different field and add getters and setters for it or delegate the methods to it.
So I'm trying to make a mysql database class, and I want to keep my db selection in a seperate method from the constructor. For some reason it the setDb() function doesn't want to work.
class mysql
{
public function __construct($server,$user,$pass)
{
if(!$this->mysql_connection = mysql_connect($server,$user,$pass))
print 'Could not connect to MySQL';
}
public function setDb($dbname)
{
$this->database = $dbname;
if(!mysql_select_db($this->database,$this->mysql_connection))
$this->database = '';
print 'Could not connect to the MySQL database';
return false;
return true;
}
private $database;
private $mysql_connection;
}
You could throw an exception in case of a MySQL error, e.g.
class DbMySQL
{
protected $database;
protected $mysql_connection;
public function __construct($server,$user,$pass)
{
$this->mysql_connection = mysql_connect($server,$user,$pass);
if( !$this->mysql_connection ) {
throw new ErrorException(mysql_error(), mysql_errno());
}
}
public function setDb($dbname)
{
if ( !mysql_select_db($dbname, $this->mysql_connection) ) {
throw new ErrorException(mysql_error($this->mysql_connection), mysql_errno($this->mysql_connection));
}
else {
$this->database = $dbname;
}
return $this;
}
}
$m = new DbMySQL('localhost', '...', '...');
$m->setDB('...');
Maybe ErrorException() is not the best choice, but I hope you get the idea ;-)
I don't see any glaring problems. Are you calling your class like below?
$db = new mysql($server, $user, $password);
$db->setDb('YOUR_DATABASE_NAME');
You need to add curly braces after your mysql_select_db line, and before the return true line. Only the first statement under the condition is executed when the condition is met. So the function always returns false.