require("classes/controller.class.php");
$db = new mysqli(__DBHOST, __DBUSER, __DBPASS, __DBDATA);
if ($db->connect_errno) {
printf("Connect failed: %s\n", $db->connect_error);
exit();
}
$controller = new Controller;
Within the Controller class I want to use the $db MySQLi connection. So within a public function I used:
$result = $db->query("SELECT * FROM colors");
var_dump($result);
But I get this error:
Fatal error: Call to a member function query() on a non-object in /home/cloud/public/teamdresser/controllers/IndexController.php on line 8
Am I doing something wrong? Do I need to pass the $db connect first, or use global or something?
Thanks in advance
If $db is a global variable, you'll need to import it in your function:
public function YourFunction()
{
global $db;
$result = $db->query("SELECT * FROM colors");
..
}
Instead of doing this, you might want to consider encapsulating $db in a database class and create it as a singleton, or, arguably better, pass it to the constructor of Controller. But that remark might lead to new discussions about design, while complete books have been written about this subject. So for now, just import the global like described above. ;)
You could use a class with a singleton instance
class Database {
private static $_instance;
public static function getInstance() {
//If the connection is not initialized, this creates it and store
if (empty(Database::$_instance))
Database::$_instance = new Database();
return Database::$_instance;
}
private $_db;
private function __construct() {
$this->_db = new mysqli(__DBHOST, __DBUSER, __DBPASS, __DBDATA);
if ($db->connect_errno) {
printf("Connect failed: %s\n", $db->connect_error);
exit();
}
}
private function __destruct() {
$this->_db->close();
}
public function query($query) {
return $this->_db->query($query);
}
}
You called in this manner
$result = Database::getInstance()->query("SELECT * FROM colors");
You have created a connection and executed with calling a function. Once the script is terminated, the connection will be autorealeased by the destructor.
This should be only a start point. You could create all functionality that you want (e.g. escape parameters, insert, update, delete, and so on...)
Let me know if you have a better title for this question :)
Up till now, I've created my factory class by doing this:
include_once('menu.class.php');
include_once('gallery.class.php');
class Factory {
function new_menu_obj() { return new Menu(Conn::get_conn()); }
function new_gallery_obj($type ='', $id='') { return new Gallery(Conn::get_conn(), $type, $id); }
/* Many more defined functions here */
}
class Conn { // DB connection }
// To create a new class object I just do this
$menu = Factory::new_menu_obj();
$gallery= Factory::new_gallery_obj('some-type','3');
Now I'm trying to do this more dynamically by using this code:
include_once('menu.class.php');
include_once('gallery.class.php');
class Factory {
private $db_conn;
private function __construct() {
$this->db_conn = Conn::get_conn();
}
public function create( $class_name ) {
if ( $this->db_conn === null ) {
$this->db_conn = Conn::get_conn();
}
return new $class_name( $this->db_conn );
}
}
class Conn { // DB connection }
// To create a new class object I just do this
$menu = Factory->create("Menu");
$gallery= Factory->create("Gallery"); // How do I pass more parameters here?
Is this the "correct way" of being efficient? :)
How can I create a new object passing variables when I do not know how many variables needs to be passed? Using a array?
1 - Factory->anything will fail, I guess you mean Factory::something in your code. Anyway, with a private constructor, you won't be able to create any instance of the Factory class outside of some static Factory method...
2 - since you use static methods, use the static keyword in your function declaration should be wise.
3 - as a side and personnal note, I'm not sure why you would want to do that. The first flavour of your class does a real factory job : it creates a consistent set of classes. And you will use another flavour of factory to create another set of similar but still consistent classes.
E.g. the Factory class creates Menu and Gallery instances, the AltFactory class creates AltMenu and AltGallery instances and so on.
But you loose this benefit with the second version of your factory. Just calling the new operator on your classes instead of calling your create construct will give you exactly the same degree of dependencies, so...
Using reflection and adding a $params parameter to your create method:
class Factory {
private $db_conn;
private function __construct() {
$this->db_conn = Conn::get_conn();
}
public function create( $class_name, $params = []) {
if ( $this->db_conn === null ) {
$this->db_conn = Conn::get_conn();
}
array_unshift($params, $this->db_conn);
$reflect = new ReflectionClass($class_name);
return $reflect->newInstanceArgs($params);
}
}
class Conn { // DB connection }
$menu = Factory->create("Menu");
$gallery= Factory->create("Gallery", ['pics' => ... ])
I have a class called DB (class.pdo.php) that does all the handling on mysql queries using PDO and another class called user that I use to manage a login system.
My question relates to always having to instantiate the $db in every public function of users so I can use DB. Is this efficient? Shouldn't I be instantiating DB inside the __construct() of users?
This is my code
require_once("../../class.pdo.php");
class user {
private $db = null;
public function __construct(){
/* Empty? */
}
public function find_by_email($email){
$db = new db();
$db->query('SELECT * FROM users WHERE email = :email LIMIT 1');
$db->bind(':email',$email);
$result = $db->single();
return $result;
}
public function create($email,$password,$first_name,$last_name){
$db = new db();
$db->query("INSERT INTO users(email,password,first_name,last_name,created_at) VALUES (:email,:password,:first_name,:last_name,NOW())");
$db->bind(':email',$email);
$db->bind(':password',$password);
$db->bind(':first_name',$first_name);
$db->bind(':last_name',$last_name);
$result = $db->execute();
return $db->lastInsertId();
}
[more similar functions ommited]
Well, despite of some comments suggesting the use of the Singleton pattern, I totaly disagree in using it for this purpose.
Your application will not always use a single connection to just one database.
Let me show you how I'd do this:
class DbConnector {
private $dbh;
private $dsn;
public function __construct($dsn) {
$this->dsn = $dsn;
}
private function connect() {
if($this->dbh === null) {
$this->dbh = new PDO($this->dsn);
}
}
public function disconnect {
if($this->dbh !== null) {
$this->dbh = null;
}
}
public function query($sql) {
$this->connect();
//... do the rest
}
public function fetchAll($sql) {
$this->connect();
//... do the rest
}
public function insert($table, $values) {
$this->connect();
//... do the rest
}
public function update($table, $values, $cond) {
$this->connect();
//... do the rest
}
public function delete($table, $cond) {
$this->connect();
//... do the rest
}
}
class User {
private $dbConn;
public function __construct(DbConnector $dbConn) {
$this->dbConn = $dbConn;
}
public function create($email,$password,$first_name,$last_name){
$this->dbConn->query("INSERT INTO users(email,password,first_name,last_name,created_at VALUES (:email,:password,:first_name,:last_name,NOW())");
$this->dbConn->bind(':email',$email);
$this->dbConn->bind(':password',$email);
$this->dbConn->bind(':first_name',$email);
$this->dbConn->bind(':last_name',$email);
$this->dbConn->execute();
return $this->dbConn->lastInsertId();
}
// ...
}
Results:
No singleton used = testable.
Connection to the database is just openned when needed
Your connection is persistent. If you open and close connections in every method, you loose the capability of creating transactions.
What about using the Singleton pattern to create one object for the connection and use it everytime you need it, instead of creating new objects all the time?
I would do something similar with lazy loading: don't initiate in the constructor unless you're sure you actually need the connection every time an object is created but absolutly don't create a new object on each method call. Instead, save the resulting object into an object var which is checked on each method call and initiates the connection if missing.
class user {
protected $_db = null;
private function _init_db() { $this->_db = new XXX; }
public function create( $x, $y, $z ) {
if ( ! $this->_db ) $this->_init_db();
# use $this->_db ..
}
public function find_by_email( $x, $y, $z ) {
if ( ! $this->_db ) $this->_init_db();
# etc
}
}
This has the advantages of avoiding global static state (singletons..) and only creates the connection / object at the very last moment so you're sure you actually need it and it's not just a useless connection.
Speaking of efficiency, the main problem with your code is that it establishes new connection for the every method called. This one is indeed inefficient to the point of killing your database server. And it's incomparable to the other problem you have.
So, in general, you can have whatever way you want - either get somehow an instance of db class in the every function or use a class variable - but either way have to use single PDO instance throughout whole application.
Also I find your functions quite inefficient from the amount of code point of view, and would have optimized them this way
public function create($email,$password,$first_name,$last_name){
$sql = "INSERT INTO users(email,password,first_name,last_name,created_at) VALUES (?,?,?,?,NOW())";
$this->db->query($sql);
$result = $db->execute(func_get_args());
return $db->lastInsertId();
}
From a object point of view, I'd leave database instantiating within the methods, rather than an entire class.
Each method should only see the variables and data it needs, in order to perform its function.
For instance, a createUser() method would need to see variables or properties such as $username, $usergroupId, as well as $database etc.
However, you may have a function which is called randomPassword(), which generates a random password from numbers and letter.
This randomPassword() function doesn't need the database object and therefore, an already initialised database connection in the object scope would be wasteful.
It would be better only to create the new database object in methods that required it.
In addition, in my application, I don't create a new database connection each time I used new database. Instead, I've opted for a singleton PDO database object which keeps the connection active.
I can then just call the database object statically to retrieve an existing connection. Therefore, if, in the process of running my application I need to have 20 database objects, my application then only returns the same object, and the same connection.
I'm reading up on php design patterns, and I saw this code:
<?php
require_once("DB.php");
class DatabaseConnection
{
public static function get()
{
static $db = null;
if ( $db == null )
$db = new DatabaseConnection();
return $db;
}
private $_handle = null;
private function __construct()
{
$dsn = 'mysql://root:password#localhost/photos';
$this->_handle =& DB::Connect( $dsn, array() );
}
public function handle()
{
return $this->_handle;
}
}
print( "Handle = ".DatabaseConnection::get()->handle()."\n" );
print( "Handle = ".DatabaseConnection::get()->handle()."\n" );
?>
I understand it all except the last two print statements. I've been messing around with it, but I don't understand the static function somehow calling a public non-static function.
I've notice I can do:
DatabaseConnection::get()->get()->get()->handle();
but I can't so something like:
DatabaseConnection::get()->handle()->get();
I just don't understand what this is doing, other than calling the get function then calling the handle function.
This works because the static function returns a new object. This type of construction is typically referred to as a Singleton, since it is attempting to enforce that only one instance of a DatabaseConnection is ever available.
Notice that the constructor is private, so you cannot explicitly call new DatabaseConnection() unless you are already inside the class. Solutions utilizing a Singleton will have a property, initally null, that is then set to a non-null value upon object instantiation. The 'getInstance' (or get in this case) method will only return a new object if the property is null.
DatabaseConnection::get() creates an instance of DatabaseConnection and returns it.
So...
DatabaseConnection::get()->handle();
...could also be written as follows...
$db = DatabaseConnection::get();
$db->handle();
I'm trying to create a simple class based on my database PDO class that I can say "get this id" and it will print the info. I'm trying to do this in "qu" but get the following error: "Call to undefined method qu::get()".
There's probably a mixture of problems so any help here would be awesome. Thanks a lot!!
class db {
protected static $conn;
private function __construct(){}
public static function connect() {
if (!isset(self::$conn)) {
self::$conn = new PDO('mysql:host=localhost;dbname=database', DB_USER, DB_PASSWORD);
}
return self::$conn;
}
}
class qu {
private $db;
function quconn (&$db){
$this->db = &$db;
}
private static function getq($id){
$sql="SELECT * FROM table WHERE id=:id";
$stmt = self::quconn()->prepare($sql);
$stmt->execute(array(':id'=> $id));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
}
//$data = db::connect()->query("SELECT * FROM table")->fetchAll(); // this works
$data = qu::getq("22"); //can i use something like this? this causes the error
print_r($data);
function getq of class qu should be marked with public access modifier.
Otherwise the following row will fail as getq is a private function
$data = qu::getq("22");
Second and issue in this code
function quconn (&$db){
$this->db = &$db;
}
As you enter function quconn from a static content $this is unavailable.
Use self::$db instead.
For class qu follow the same structure of class db wich is a singleton mnagament class.
I also suggest to clarify yourself differences between $this and self, static contest etc..
Php offiacial documentation offers al lot about
Also i don't think you need passing-by-reference method:
try to rewrite the quconn function as follows:
function quconn ($db){
self::$db = $db;
}
By the way i don't thing the class qu is well "engineered"
Even if you correct the passing-by-reference-problem this instruction won't work:
$stmt = self::quconn()->prepare($sql);
You are invoking the prepare function on the result of the invocation to quconn, which doesn't return anything...
I suggest:
$stmt = db::connect()->prepare($sql);
this get the PDP instance and call the prapare method....