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();
Related
Im making a PDO system and got a problem/question. I gonna make multiple classes for my codes, for users, products etc. And I was wondering about the connection. I have this in one of my classes:
class Database
{
private $_db;
function __construct($db)
{
$this->_db = $db;
}
}
$db comes from a config file, where I also load all the classes in. The question is now:
Do I have to create the same function in all the classes or can i just have my "database" class that work for all my classes?
No, you don't have to (and shouldn't) create the same function over and over again for every class. That makes it very hard to maintain your application.
Try one of the following methods:
1. Dependency Injection
You can use dependency injection to do this. This is very situational and probably not what you're looking for, but I thought I'd put it here anyway.
Assume the following:
class Database
{
/**
* #var PDO
*/
private $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
}
class User
{
/**
* #var Database
*/
private $db;
// Here we inject a Database object (as hinted by Database $db) into the current instance
public function __construct(Database $db)
{
$this->db = $db
}
}
try
{
$pdo = new PDO(...);
$db = new Database($pdo);
}
catch(PDOException $ex)
{
// Could not connect to database or some other error message
}
// Inject $db in the user class
$user = new User($db);
2. Singleton
You can make your Database class a singleton and then call it statically. This might be more what you need.
class Database
{
/**
* #var Database
*/
private static $instance;
/**
* #var PDO
*/
private $db;
protected function __construct(PDO $db)
{
$this->db = $db;
}
// You'd call this in your config
public static function initialize(PDO $db)
{
if(self::$instance == null)
{
// Create a new instance of this class
self::$instance = new self($db);
}
}
// Get the instance
public static function getInstance()
{
return self::$instance;
}
// Do something
public function doSomething()
{
// Do something
echo "Foo";
}
}
class User
{
public function doSomething()
{
// This would print "Foo"
Database::instance()->doSomething();
}
}
try
{
$db = new PDO(...);
}
catch(PDOException $ex)
{
// Could not connect to database or some other error message
}
Database::initialize($db);
$user = new User();
Hope this helps.
I'm trying to create the skeleton of a basic framework, but I've stumbled on a situation in which I find myself with some piece of the engine that is missing.
I have this class to manage MySQL connections:
class Mysql implements IConnection {
protected $user;
protected $pass;
protected $dbhost;
protected $dbname;
protected $dbh;
public function __construct($user, $pass, $dbhost, $dbname)
{
$this->user = $user;
$this->pass = $pass;
$this->dbhost = $dbhost;
$this->dbname = $dbname;
}
public function connect()
{
// implementation
}
public function prepare($query)
{
// implementation
}
}
Now I want to use a factory + singleton to manage a sole instance of this class:
class Database
{
private static $db;
private function __construct() {}
public function getInstance($DBType = 'mysql')
{
if (! isset(self::$db)) {
switch ($DBType) {
case 'mysql':
self::$db = new Mysql(); // <---- PROBLEM HERE!!
// more database types should follow
}
}
return self::$db;
}
}
Note that this way I should pass the factory method the connection parameters everytime I needed the database connection instance, which definitely wouldn't be convenient.
The only thing that comes to mind is to pass the db connection, previously created, to Mysql::__construct() and store it in a property, in order to use in within Mysql::prepare(), but it would break the interface: Mysql::connect() wouldn't make any sense, and I couldn't have the db connection wrapped in this class together with the query management.
What would you suggest me to do?
EDIT:
This is my own try, although I would need to change the interface, and I'm not sure if it would be a good approach:
- Changing the interface so that IConnection::connect() accepts the connection parameters instead of the constructor
class Mysql implements IConnection {
protected $dbh; // now I only need this property
public function __construct()
{
}
public function connect($user, $pass, $dbhost, $dbname)
{
// implementation
}
public function prepare($query)
{
// implementation
}
}
And the Singleton Factory:
class Database
{
private static $db;
private function __construct() {}
public function getInstance($DBType = 'mysql')
{
if (! isset(self::$db)) {
switch ($DBType) {
case 'mysql':
self::$db = new Mysql;
break;
case 'mssql':
self::$db = new Mssql;
break;
case 'postgresql':
self::$db = new Postgresql;
break;
// etc
}
}
return self::$db;
}
}
I think this way is clean enough. Some client code:
$db = Database::getInstance(Config::get('db_driver'));
$db->connect(Config::get('db_user'),
Config::get('db_pass'),
Config::get('db_host'),
Config::get('db_name'));
Suggestions and corrections are most welcome.
I am trying to learn some more PHP, OOP and MySQLI, but I am stuck. Google didn't help me and searching on this website didn't give me any results either. I have a config class to connect to the database, and in another class I want to run some queries, but I am getting this error with whatever I am trying:
Fatal error: Call to a member function query() on a non-object in
test.php on line 9
Can someone please help me?
config.php:
<?php
class Database
{
private $host;
private $user;
private $password;
private $db;
private $mysqli;
function __construct() {
$this->host = "private";
$this->user = "private";
$this->pass = "private";
$this->data = "private";
$this->mysqli = new mysqli($this->host, $this->user, $this->pass, $this->data);
}
public function query($query)
{
return $this->mysqli->query($query);
}
}
?>
test.php:
<?php
class Dummy
{
private $Database;
function __construct()
{
$this->Database = new Database();
$this->Database->test = $this->mysqli->query("SELECT test FROM test")->fetch_object()->test;
}
}
?>
index.php:
<?php
require 'config.php';
require 'test.php';
$test = new Database();
$test = new Dummy();
echo $this->Database->test;
?>
How about using Dependency injection, create the Database object then pass that as a parameter to the class through the construct.
<?php
class Database
{
private $host;
private $user;
private $password;
private $db;
private $mysqli;
function __construct($host,$user,$pass,$data) {
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->data = $data;
$this->mysqli = new mysqli($this->host, $this->user, $this->pass, $this->data);
}
public function query($query)
{
return $this->mysqli->query($query);
}
}
?>
...
<?php
class Dummy
{
function __construct(Database $db)
{
$this->db = $db;
}
function get_test_yada(){
return $this->db->mysqli->query("SELECT test FROM test")->fetch_object()->test;
}
}
?>
...
<?php
$db = new Database('127.0.0.1','root','pass','database');
$dummy = new Dummy($db);
$dummy->get_test_yada();
?>
Untested, hope it helps
For the goodness sake, DON'T learn them all at once. You won't get any sensible result.
Each is a hard and complex topic alone, of which OOP is hardest.
For the database interacton use PDO prepared statements.
As the OOP practice, never extend class from a service, but use it as a class variable.
class Dummy
{
protected $db;
function __construct($pdo)
{
$this->db = $pdo;
}
}
$this->mysqli = new mysqli($this->host, $this->user, $this->pass, $this->data);
If connecting fails, you can't call anything on that member variable. Check if your connection is established first.
And, if you want to have access to that variable, you should make it public.
I need to use $GLOBALS['db'] in my classes ($db is defined in my index.php), but I don't want to use $GLOBALS['db'] when I have to call it.
I wrote this code at the beginning of my classes :
class ClassName
{
var $db;
public function __construct()
{
$this->db = $GLOBALS['db'];
}
public function test()
{
$val = $this->db->oneValue('SELECT first_name FROM users LIMIT 0, 1');
echo $val->first_name;
}
}
But I'm not enjoying this; I prefer to use directly $db in my code. Is there a solution to be able to call $GLOBALS['db'] by $db?
Simples, just inject in the constructor or a setter method: (I'm assuming $db is an object here, not an array of connection parameters etc)
class ClassName
{
protected $db;
public function __construct($db)
{
$this->setConnection($db);
//Any other constructor things you want to happen...
}
/*
* This is just here for convenience, this could be protected if you only want to set
* the db connection via the constructor
*/
public function setConnection($db)
{
$this->db = $db;
}
public function test()
{
$val = $this->db->oneValue('SELECT first_name FROM users LIMIT 0, 1');
echo $val->first_name;
}
}
As mentioned in some comments above, this is a form of dependency injection which will give you more ability to re-use code inside your project (A Good Thing TM).
I prefer using singleton pattern for databases.
this is the DB class i am using for my app.
class Database {
protected static $_dbh;
const HOST = 'localhost';
const DATABASE = 'dbname';
const USERNAME = 'username';
const PASSWORD = 'password';
private function __construct() { }
public static function getInstance() {
if(!isset($_dbh)) {
try {
#Connection String.
self::$_dbh = new PDO('mysql:host='.self::HOST.';dbname='.self::DATABASE,self::USERNAME,self::PASSWORD);
self::$_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
#Print Errors.
echo $e->getMessage();
}
}
return self::$_dbh;
}
}
as i am using singleton pattern the connection will be re-used. you can now use the connection everywhere in your app by calling static connection method i.e
class ClassName
{
protected static $_dbh;
public function __construct() {
self::$_dbh = Database::getInstance();
}
public function test() {
$sth = self::$_dbh->query('SELECT first_name FROM users LIMIT 0, 1');
$row = $sth->fetchAll(PDO::FETCH_ASSOC);
echo $row['first_name'];
}
}
Hope you can help me with this one: i have two classes: Database and Users. The Database connects to the database using PDO (inside the constructor) and has functions to alter tables, insert data, etc. The Users class will handle login, as well add/remove users. However, the Users class needs to connect to the database. How can i do this?
There are several things you could do:
Globals
$db = new Database();
class Users
{
public function foo()
{
global $db;
$db->query();
}
}
Setting a static variable
$db = new Database();
class Model
{
static public $db;
}
Model::$db = $db;
class Users extends Model
{
public function foo()
{
self::$db->query();
}
}
Use a singleton
class Database
{
private static $instance;
private function __construct()
{
}
public static function instance()
{
return self::$instance ? self::$instance : self::$instance = new self();
}
}
class Users
{
public function foo()
{
Database::instance()->query();
// or $db = Database::instance(); $db->query();
}
}
The one thing you want to avoid is creating a new database connection per model or class.
Same way you normally would, but it might help to make the database a class property:
<?php
class Users
{
protected $_db;
public function __construct(Database $database = null)
{
if (!$database) {
$database = new Database;
}
$this->_db = $database;
}
public function addUser($username)
{
// Do stuff ...
$this->_db->insert($data);
}
}
Then you can use the User class like:
<?php
$users = new Users;
$users->addUser('joebob');
Simply add a reference to the database class instance into Users:
class Users {
var $database;
function __construct() {
$this->database = new Database();
}
};
Alternatively, if Database is a singleton, just reference it directly.
One way to do so would be to create ONE shared instance of the database class, then use it as a global variable wherever needed.
Start by creating the instance anywhere in your project, just make sure it is in global space (not inside another class or function).
$DB = new Database();
Then to access the shared database object, just use the $GLOBALS built-in array:
class User {
function __construct() {
$DB = &$GLOBALS['DB'];
// do something
$DB->callSomeMethod();
}
...
}
As pointed out by #Ryan, namespace collisions are possible using this strategy. The best middle path out would be to convert the Database class into a singleton. Then it would store its own instance (translation: ONE connection no matter what) which could be accessed via a Database::getInstance() method.
This is my Users class:
class Users {
private $data;
private $db;
public function __construct() {
$db = Database::getInstance('localhost', 'database', 'root', '123456');
}
public function __get($key) {
return $this->data[$key];
}
public function __set($key, $value) {
$this->data[$key] = $value;
}
public function test() {
foreach($this->db->query('table', '*', '', '', '', '', '0,5') as $value) {
$results .= $value['field1'] . "<br />";
}
return $results;
}
}