I have a Database class for connecting to DB.
<?php
require_once('config.php');
class Database {
function __construct(){
$this->connect();
}
public function connect(){
$this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE);
}
}
?>
And a main class where I need to use the DB connection:
include 'includes/database.php';
class Main{
var $mysqli;
public function __construct(){
$this->mysqli = new Database();
}
But this is not working, since I get an error for queries that are still in the main classes, I intend to move them to the DB class later. But now I am getting an error:
Fatal error: Uncaught Error: Call to undefined method
Database::query() in /home/vagrant/Projects/MyProject/index.php
on line 262
Queries are done in the Main class:
$result = $this->mysqli->query( "SELECT shops.*, shops.id AS shop,SUM(price)...
You are trying to call a query() method on the Database class. While that class contains a mysqli object in its $connection property, it does not expose the query() method of that mysqli object.
Given your current code, you could drill further into the object structure to call query() directly on the mysqli, but this is messy.
// Call the query() method directly on the connection
$result = $this->mysqli->connection->query( "SELECT shops.*, shops.id AS shop,SUM(price)...
I don't like this approach because it requires that your classes know more about the inner workings of the Database class than they probably should. It couples them too tightly.
As an alternative, you could create a query() method in the Database class that wraps the necessary functionality of the mysqli object within it.
class Database {
function __construct(){
$this->connect();
}
public function connect(){
$this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE);
}
// Expose a query() method that calles the inner mysqli's query
public function query($sql) {
return $this->connection->query($sql);
}
}
This would allow you to pack in more functionality, such as querying and fetching all result rows in one method call:
class Database {
//....
// A more featured query() that returns the
// rows as an array
public function query($sql) {
$result = $this->connection->query($sql);
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
// Return an array of all the rows fetched from the query
return $rows;
}
}
If you do it this way, you should be able to call $this->mysqli->query("...") as you originally attempted and either get back the result resource with the simple version, after which you must fetch in the code yourself, or get back an array of associative result rows in the more featured version.
Creating these kinds of database wrapper classes can get unwieldy rather quickly though. Think carefully about what aspects of the mysqli object you want to expose to the other classes in your application. It's not a good idea to go down a path of wrapping every mysqli method in your Database class. At that point, the utility of the Database class is greatly reduced and you may as well just be passing in a mysqli object directly. If you are not actively adding functionality to mysqli, it makes less sense to create another class that wraps it.
A note about the var $mysqli;... This is an old deprecated class property syntax. The var keyword is a vestige from PHP4 and its use is discouraged nowadays. In fact, it has been removed from recent PHP versions. Instead, you should declare it via the PHP5+ syntax:
// Declare as a public property
public $mysqli;
// Or better, as a private (or protected) property so it cannot
// be accessed outside the Main class' own methods
private $mysqli;
In your question title, you mentioned injection. Your class doesn't do that right now, but it would be a good idea to instantiate a Database ahead of time and inject one into the class constructors that need it.
class Main{
public $mysqli;
// Pass a database as a constructor param
public function __construct($database){
$this->mysqli = $database;
}
Then instantiate it as:
$db = new Database();
// Pass the $db to the other classes
$main = new Main($db);
Importantly, this will prevent you from opening up a separate database connection for each object you instantiate of Main and any other class you construct in the same way. Doing that can quickly use up the server's available MySQL connections.
Related
I have a CMS that is failing when more than one person is logged in. I think the problem may be that I'm not closing databases properly. Here is the basic setup:
I have a master class called Mysql. The __construct() method looks something like this:
class Mysql {
protected $conn;
function __construct() {
if(!$this->conn) $this->conn = New mysqli(SITE_HOSTNAME, SITE_USERNAME, SITE_PASSWORD, SITE_DATABASE);
}
All of my classes are descendants of this class, and so whenever they are instantiated, they get their own connection.
I'm using prepared statements to protect against sql injection. A sample method might look like this:
function foo($blog = 0) {
$query = "SELECT catid, catname
FROM category
WHERE blog = ?
ORDER BY catname ASC";
$result = array();
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('i', $blog);
$stmt->execute();
$stmt->bind_result($catid, $catname);
while($stmt->fetch()) $result[$catid] = stripslashes($catname);
$stmt->close();
return $result;
}
}
The Mysql __destruct() method looks like this:
function __destruct() {
if($this->conn) $this->conn->close();
}
Is my problem that I am not closing my connections properly, or that I do not have enough active connections?
My provider says that I have 30 simultaneous connections available. Not enough?
Thanks for your help.
The Problem
All of my classes are descendants of this class, and so whenever they
are instantiated, they get their own connection.
The problem with the way you are doing it is that every single instance of any class that inherits Mysql is opening a connection to the Mysql server that lives until the request is completed, or the variable destructed (unless you are killing these objects manually, that's at the end of the request). If you have 30 instance of classes like this, then you have maxed out your connections.
Fixing The Problem
Your classes shouldn't all be inheriting this Mysql class that represents your interface to the database.
Instead, you should be passing a single instance of this Mysql class where it's needed.
There are two ways this could be done effectively:
Dependency Injection
class SomeClass {
protected $db;
public function __construct(Mysql &$db) {
$this->db = $db;
}
public function functionThatNeedsDatabase() {
$this->db->doSomethingWithTheDatabase();
}
}
$db = new Mysql(); //A single instance of Mysql class has been created.
$someClass = new SomeClass($db);
$someClass->functionThatNeedsDatabase();
Pass to Method When Needed
class SomeClass {
public function functionThatNeedsDatabase(Mysql &$db) {
$db->doSomethingWithTheDatabase();
}
}
$db = new Mysql(); //A single instance
$someClass = new SomeClass();
$someClass->functionThatNeedsDatabase($db);
Your problem is "All of my classes are descendants of this class, and so whenever they are instantiated, they get their own connection." In PHP connection are automatically closed when the script ends. You really only need 1 connection per user. You should create an instance of your DB class and pass that object into all the classes that need to use it (Dependency Injection pattern).
30 connections is not a whole lot, but that is sufficient for a lot of traffic. I would avoid using persistent connections. Read the documentation thoroughly on that, there are plenty of warnings.
This question already has answers here:
Call to a member function on a non-object [duplicate]
(8 answers)
Closed 9 years ago.
I'm working with a few different classes across different php files. For some reason, the first time I call my function, it works correctly, but the second call results in an error.
This is my "something" class (edited for public view)
class something{
private $db;
function myfunction($sql){
$db = new db();
$results = $db->select("sql query using $sql");
return(empty($results[0]['name'])?0:1);
}
}
"db" is another class I'm using to handle the database queries etc. I don't believe the issue lies in this file since the first call works correctly.
Here's the code I'm using to test it. This is in a different php file from the "something" class.
$something = new something();
echo($something->myfunction('string'));
echo($something->myfunction('string2'));
As I mentioned, the first call ("string") works correctly, but the second one ("string2") fails. This is the error I get.
Call to a member function select() on a non-object
I don't believe it's an issue with the select function (or the db class) since the first call works correctly. I think the issue lies with me declaring $db in "myfunction", but I'm not sure why.
First off, I would shy away from creating a new $db every time you call that function unless you're going to explicity destroy it at the end of the function call.
Secondly, you are creating the class variable private $db but you aren't assigning the db object to it.
You should try the following:
class something{
private $db;
function myfunction($sql){
if(!isset($this->db)){
$this->db = new db();
}
$results = $db->select("sql query using $sql");
return(empty($results[0]['name'])?0:1);
}
}
I feel like that should work better. Let me know!
Edit:
Right- so either do it as my code above shows, or use the class constructor to do it. In PHP the constructor object isn't the class name, it is defined as __construct()
My approach would be either to extend the DB class as I mentioned in my comment above, or to do it in the constructor. My reasoning behind that is because I just don't like creating class-instances inside of methods if I can avoid it, I'd rather make it once when the object is created. SOoooooOOOoOOoOOo:
class something{
private $db;
public function __construct(){
$this->db = new db();
}
function myfunction($sql){
$results = $this->db->select("sql query using $sql");
return(empty($results[0]['name'])?0:1);
}
}
Notice the usage of $this->
That's a PHP thing. Get familiar with it if you aren't- you'll be using it a BUNCH. :)
Good luck!
What kind of DB wrapper are you using? Is database persistence turned on? It migth be disconnecting and not reconnecting the second time round, thus returning an empty DB object.
Can I assume that this is a short version of your code, and you have some logic to instantiate $db only once? In that case you must change that line from
$db = new db();
to
$this->db = new db();
Otherwise db object will be gone at the end of the call.
I have a class userdb in which I am declaring a function that returns the connection to the database:
return $con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
I have various functions, even across other classes, where I have to access $con (e.g. to pass a query or to fetch data), but I can't access this variable.
Is there a better way to define and use a database class? Remember that I have other classes where I need to access the userdb class.
I would advise you to use the Singleton Pattern for this:
In your userdb class, declare a static property $scon:
private static $scon;
and assuming the function you mention above is named createConnection(), you should create the folowing static method:
public static function connect() {
if (empty(self::$scon)) {
$instance = new userdb();
self::$scon = $indtance->createConnection();
}
return self::$scon;
}
With this, you will be able to access your userdb connection with:
userdb::connect();
Also since this is a singleton, it will only connect once, and use that connection until the end of the script.
Note (on dependency injection): Since #KevinM1 mentioned Dependency Injection, I must add that it is also a possible, and far superior solution. It requires you to create a setConnection() method (or an Abstract ancestor) for all your classes using a database connection, and during the instatiation of these classes you may use a Factory to add the required connection to the object. This should be wrapped inside some class loader, which is avare of your model structure.
See, peace of cake, but for small and fast developement I would stick with the Singleton ;)
If it's in a class, store the instance in a property:
class userDB
{
public $dbCon = false;//because you want to access the instance
//from outside the class, I have made the property public
function connect()
{
$con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
$this->dbCon = $con;
}
}
TO access it outside of the class:
$useDBInstance->dbCon;
return $this->con
return this way from your class and call it this way..
$this->classObject->con->prepare();
Checkout my video tutorial + code for an alternative to global PHP variables.
You're doing it wrong there. You need to use a static variable if you plan to create your connection in a function and store it there. Otherwise you'll keep connecting on every function call. My tutorial explains this very concept of static variables within regular functions.
If it's not clear enough, let me know and I'll try to answer your questions.
Here's some code to accompany this:
/**
* Arguments are none or [$db, [$user, [$pass[, $host]]]].
*
* #return PDO
*/
function PdoDb(){
static $con = null; // I'm explicit :)
// Every time you pass Arguments you reconnect
if(func_num_args()){
$args = array_pad(func_get_args(), 4, null);
list($db, $user, $pass, $host) = $args;
if(empty($user)) $user = 'root';
if(empty($host)) $host = 'localhost';
$con = new PDO("mysql:host={$host};dbname={$db}", $user, $pass);
}
if(empty($con)){
trigger_error('Provide arguments to connect first.', E_USER_ERROR);
return null;
}
return $con;
}
// First run (provide arguments to connect)
PdoDb($db, $user, $pass, $host);
PdoDb($db); // Works if you connect root#localhost with no password
// From here on (it returns PDO)
PdoDb()->DoStuffOfPdo();
Once connected it stays that way. But you can reconnect at will to by providing arguments.
Well, $con will already be an object, as it's instantiating a new PDO object. Unless you're trying to add functionality to your PDO object, wrapping it is pointless.
That said, the best way to share your userdb/PDO object (depending on whether or not you stick with the wrapper) with other objects is to use Dependency Injection. That's a fancy term for passing your db to whatever object needs it. Since objects are defaultly passed by reference in PHP, if you create your db object first, all objects that receive it as a constructor/method argument will be using that same single instance.
EDIT: Link to Dependency Injection implementation
EDIT2: Clarification on DI in small projects -
The normal DI pattern generally requires a special object called a DI Container. This is a special use object that automatically injects the dependency into the object that needs it. For small projects, it's overkill. The simple, low complexity version of DI is simply:
class SomeClass {
protected $db;
public function __construct($db) {
$this->db = $db;
}
}
class SomeClass2 {
public function SomeMethod($db) {
// do something with the db
}
}
$db = new PDO(/* connection string */);
$obj = new SomeClass($db, /* other constructor args */);
// or
$obj2 = new SomeClass2(/* constructor args */);
$obj2->someMethod($db, /* method args */);
The magic is that since objects are passed by reference by default in PHP, $obj and $obj2 are using the same db connection.
The whole idea is to not blow apart scope or encapsulation by having a static method, and to ensure that classes and their methods are up front about what they require in order to work.
Singletons do the exact opposite. They're accessed through static methods, which bypass scope, and since they're invoked and not passed, they never show up in method signatures, so anyone not familiar with the code won't be aware of that hidden requirement. Even Erich Gamma, one of the people who helped codify the Singleton Pattern has regrets about it:
I'm in favor of dropping Singleton. Its use is almost always a design smell.
In PHP, where there's no concept of shared memory, and where scripts execute once per request, the only reason to want to use a singleton is to have easy access to a single resource. Since objects are passed by reference, a single instance can be shared with multiple objects naturally. From there, it's about good design and delegation.
use singlton class implimentation
class connectdb
{
protected static $_instance = NULL;
private function __construct()
{
}
public function getinstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function connect()
{
$this->connection =new PDO("mysql:host=$host;dbname=$db", $user, $pass);
}
}
for using a variable within a class function or independent function you need to place a global keyword
$conn=mysql_connect();
function test(){
global $conn;
}
now $conn will be available within the scope of test function, and it will be available everywhere when defined at the top of the script. For class also you need to do the same thing, make a object of a class and declare it as global within a function
I'm trying to create a pagination class and use a variable from outside the class.
But it's giving me the fatal error "Call to a member function query() on a non-object".
This is the index file:
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new pagi();
$records = $pagination->get_records("SELECT * FROM `table`");
And this is the pagi.php file:
class pagi {
public function get_records($q) {
$x = $db->query($q);
return $db->fetch($x);
}
}
Is it possible to use this variable from out side of the class inside the class, without creating a new one inside the class?
The correct way to solve this would be to inject the database object into the other class (dependency injection):
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new Paginator($db);
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`");
class Paginator
{
protected $db;
// Might be better to use some generic db interface as typehint when available
public function __construct(DB_MySQL $db)
{
$this->db = $db;
}
public function get_records($q) {
$x = $this->db->query($q);
return $this->db->fetch($x);
}
}
Another way you could solve it is by injecting the instance of the database class into the method that uses it:
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new Paginator();
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`", $db);
class Paginator
{
public function get_records($q, DB_MySQL $db) {
$x = $db->query($q);
return $db->fetch($x);
}
}
Whichever method you choose depends on the situation. If only one method needs an instance of the database you can just inject it into the method, otherwise I would inject it into the constructor of the class.
Also note that I have renamed your class from pagi to Paginator. Paginator is a better name IMHO for the class because it is clear for other people (re)viewing your code. Also note that I have made the first letter uppercase.
Another thing I have done is changed the query to select the fields you are using instead of using the "wildcard" *. This is for the same reason I have changed the classname: People (re)viewing your code will know exactly what fields will be retrieved without checking the database and/or the result.
Update
Because answer gave rise to a discussion regarding why I would go the dependency injection route instead of declaring the object global, I would like to clarify why I would use dependency injection over the global keyword: When you have a method like:
function get_records($q) {
global $db;
$x = $db->query($q);
return $db->fetch($x);
}
When you are using the above method somewhere it isn't clear that the class or method uses depends on $db. Hence it is a hidden dependency. Another reason why the above is bad is because you have tightly coupled the $db instance (thus the DB_MySQL) class to that method / class. What if you need to use 2 databases at some point. Now you would have to go through all code to change global $db to global $db2. You should never need to change your code just to switch to another database. For this reason, you should not do:
function get_records($q) {
$db = new DB_MySQL("localhost", "root", "", "test");
$x = $db->query($q);
return $db->fetch($x);
}
Again, this is a hidden dependency, and tightly couples the DB_MySQL class to the method / class. Because of this it is also impossible to properly unit test the Paginator class. Instead of testing only the unit (the Paginator class) you are also testing the DB_MySQL class at the same time. And what if you have multiple tightly coupled dependencies? Now you are suddenly testing several classes with your so called unit tests. So when using dependency injection you can easily switch to another database class, or even a mocked one for testing purposes. Besides the benefit of testing only one unit (you don't have to worry about getting wrong results because of dependencies) it will also make sure your tests will finish fast.
Some people may think the Singleton pattern is the correct way to get access to a database object, but it should be clear, having read all of the above, a singleton is basically just another way of making things global. It might look different, but it has the exact same characteristics and hence the same problems as global.
Although I do agree that the dependency model is nice, for the database, I personally use a static connection that is available to all instances of the database class and the create instances to query whenever I need one. Here is an example:
<?php
//define a database class
class DB {
//the static connection.
//This is available to all instances of the class as the same connection.
private static $_conn;
//store the result available to all methods
private $result;
//store the last query available to all methods
private $lastQuery;
//static connection function. connects to the database and stores that connection statically.
public static function connect($host, $user, $pass, $db){
self::$_conn = mysqli_connect($host, $user, $pass, $db);
}
//standard function for doing queries. uses the static connnection property.
public function query($query){
$this->lastQuery = $query;
$this->result = mysqli_query(self::$_conn, $query);
//process result, return expected output.
}
}
//create connection to the database, this connection will be used in all instances of DB class
DB::connect('local', 'DB_USER', 'DB_PASS');
//create instance to query
$test = new DB;
//do query
$test->query("SELECT * FROM TABLE");
//test function
function foo(){
//create instance to use in this function
$bar = new DB;
//do query
$bar->query("SELECT * FROM OTHER_TABLE");
//return results
return $bar->fetchArray();
}
That way I can create all the instances I want of DB within any function, method...etc and use that local instance of the class to do all my queries. All instances use the same connection.
One thing to note though is that this only allows for one connection to the database per defined class but I only use one so this isn't an issue for me.
you could add the db-connection ($db) to the call of the get_records method:
Here are only the relevant lines of code:
First file:
$records = $pagination->get_records("SELECT * FROM `table`", $db);
Second file:
public function get_records($q, $db) {
The other answers thus far are definitely preferable to using a global since that will ruin your encapsulation (eg you'd need to have that object defined prior to calling that method).
It's much better to enforce that in the method signature or not use a class.
I am trying to set up a MySQL connection in a main script, and then call various functions depending on what I want to do. I am having trouble passing the connection information to the function.
I have a class "queries" which contains various functions, all which return an array. This is what the code looks like in my main script (calling function normal)
$mysqli = new mysqli($db_host, $db_user, $db_pass, $db_name) or die (mysql_error());
$stats = $queries->normal($mysqli);
And then inside of the queries resource, I have this code:
class queries {
function normal($mysqli) {
$query = "SELECT number, first, last FROM roster";
$roster = $mysqli->query($query);
Then I proceed to do what I need. I cannot get this to work though. I get the error
Call to a member function normal() on a non-object
on the line that I call the function in my main file.
This is similar to these questions, but I can't quite figure it out.
Passing database connection by reference in PHP
Ensuring MySQL connection works in PHP function
Thank you
$queries is not an object, much less a queries object. Figure out what you assigned to it instead, and assign the right thing to it :)
Ahh, I think I get it now. queries is a class, not an object. You need to make an object that is an instance of the class.
$queries_obj = new queries;
$queries_obj->normal($mysqli);
"Call to a member function normal() on a non-object" means that you are trying to call normal() on a variable that is not an object. Probably you meant to do this:
$queries = new queries();
$stats = $queries->normal($mysqli);
Think of your class definition as a recipe and the object as the actual dish you made using that recipe.
As stated by others, you likely haven't instantiated (created) an object of that class.
I would really not recommend structuring your code like this. Passing around the mysql connection can make your function signatures incredibly cluttered. Two other options are:
Singleton Pattern: Encapsulate your database interaction functions into a single class, and then every time you need to call one of them, you grab an instance of that class. What's nice about this method is that you always get the same db connection, instead of opening many request. If you're not using heavy OO (lots of procedural php, or lots of global functions), this is really helpful. For example:
public function foo() {
$results = Db::getInstance()->query("SELECT * FROM bar");
// Do other stuff
return $results;
}
Inheritance: This pattern is really helpful if you're working in something like MVC, or you need to have objects share functionality. Combined with a singleton, you keep a single db connection per request, and the easy access of the db instance in a member variable.
class DB {
public function __construct() {
$this->conn = Db::getInstance();
}
}
class Foo extends DB {
public function foo() {
$this->conn->query("SELECT * FROM bar");
}
}
Whilst i could agree that passing database handlers around in methods/functions isn't probably the best idea, it's not dirty to pass database objects through to classes via the constructor, especially if you have multiple connections.