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.
Related
I am currently working in PHP and have begun to utilise classes- I am learning a lot, however I am yet to have my "penny drop" moment- I am struggling with object interaction.
I'd really appreciate some clarification in regards to how one object should interact with another. As a very basic example if I have a database object which handles connecting and querying a database, how should other classes access the results of queries performed by the database object?
From my understanding so far, I can see 2 options. Either the query results within the database class are accessible publicly and are passed to other objects as arguments...
$databaseObject = new DatabaseObject;
$databaseObject->query("query goes here");
$newObject = randomObject;
$newObject->doStuff($databaseObject->query())
Or objects which rely on query results instantiate new database objects within themselves and therefore the results are contained within that object.
class databaseConnection {
public $queryResults;
function __construct {
connect to database...
}
function query {
perform queries...
$this->queryResults = query results
}
}
class NewObject
{
function doStuff() {
$db = new databaseConnection
do stuff with $db->queryResults
}
}
Option 1 seems wrong as properties in the database class are available globally, whereas option 2 seems to contradict the idea that classes should only hold methods and properties relating to the object they define.
I could think of many other examples. If I create a class responsible for managing a user throughout a system, yet classes responsible for other tasks need to know what privilege level a user has, do I make that property within the user class global and pass it to other classes? Do the other classes instantiate new user objects?
Any help much appreciated.
Either the query results within the database class are accessible publicly
This (for me) is the key to the answer. If you set or change a value in the instance, this rather implies that you want to set the value in the underlying dataset (although you might consider defering the write). Note that the magic methods allow you to associate actions with get and set operations implicitly. But not every query is updateable. If your sql is baked in, then you can determine the updatability at design time.
Also, I suggest that your query object has a set of record objects associated with it where you interact with the underlying data. Bundling the connection functionality in the same object as the query only really makes sense if it is a factory (supporting multiple queries) and creating query result objects. And the query (result) object should probably implement the iterator interface.
Both pdo and mysqli seperate the connection, query and results into seperate objects - for good reason.
class Connection {
public static $conn;
public static function getInstance() {
if (!self::$conn) {
self::$conn = new Connection();
}
return self::$conn;
}
public function query() {
echo "run your query here using self::\$conn object";
}
}
class Person {
public function doStuff() {
$conn = Connection::getInstance();
$results = $conn->query();
}
}
$person = new Person();
$person->doStuff();
Firstly, you want to get your database connection only one time rather then opening it every time.
Secondly, using the same database connection object you can run multiple queries as shown in the above example.
You will always get a single connection no matter how many other classes you use.
I'm in the process of re factoring a lot of code to make it more testable and I have a bunch of useful functions that rely on an instantiated database object.
Things like this:
function id_from_name($table, $name)
{
$db = get_database();
//code that returns an id
}
function username_from_user_id($id)
{
$db = get_database();
//code that returns a username
}
There are a bunch more like id_exists, id_active etc.
Now I'm thinking that this isn't the right thing to do as the object should probably be passed through as an argument? But then that means creating and sending in a new object into each of these functions every time i want to use one.
So really, my questions are: Should I be moving these functions into their own class/library that has access to the database object? and are the examples that I've shown above generally a bad way of doing things?
A better approach would be indeed to make classes. And you would be passing the database object to the constructor and make it an instance variable. That way every function would have access to the database object.
Now the reason why it is considered bad to instantiate e.g. your database object in every function, is because if you decide for example one day to change your datasource, you might need a huge refactor. If you pass your database object into the constructor, you can just pass/inject the right object into the class without any refactor.
...a bit more about DI below...
By passing your objects into the constructors, you also create a more clear API => you know which object depends on the other, you know exactly which class uses your DB object. If you start instantiating it or accessing it in a static way inside the functions like you did, I would have to look through all your classes to see where your DB object is used. One more point, dependency injection forces SRP (single responsibility principle) => if you start injecting too many objects (constructor gets many arguments), you should suspect your class is doing too much than what it should, and start refactoring.
You can create a class Table_Adapter and instantiate database object inside its constructor:
class Table_Adapter
{
protected $db;
public function __construct()
{
$db = get_database();
}
}
Then you create a child class Items_Table_Adapter' that extendsTable_Adapterand put their all methods related toItems` table.
class Items_Table_Adapter extends Table_Adapter
{
public function item_by_id($id)
{
}
}
Then you use it like:
$tableAdapter = new Items_Table_Adapter();
$item = $tableAdapter->item_by_id(1);
Try something like:
class YourClass{
public static function get_database(){
// your creation
return $db;
}
public function id_from_name($table, $name)
{
/* your code */
//code that returns an id
}
public function username_from_user_id($id)
{
/* your code */
}
}
so you could just use it this way:
$db = YourClass::get_database();
$result = $db->id_from_name($table, $name);
It is certainly recommended that you have the option to swap out your database connection.
Now, if your function get_database() looks like this:
function get_database() {
static $db;
if (!$db)
$db = new \mysqli(...);
return $db;
}
Then you really, really should change it to a wrapper around a class, looking like this:
function get_database_manager() {
static $dbmgr;
if (!$dbmgr)
$dbmgr = new DbManager;
return $dbmgr;
}
function get_database() {
return get_database_manager()->getCurrentConnection();
}
where DbManager has an instance attribute with the current connection that is returned with getCurrentConnection(). If you want to swapt out the connection, do something like get_database_manager()->setConnection($newConn). Problem solved :)
I'll leave the downsides of static programming here (it remains with many examples in this thread): http://kunststube.net/static/
as well as the common method to get rid of that (we have another approach here): http://en.wikipedia.org/wiki/Dependency_injection
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'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 have one database wrapper class. How should I use this class object to execute query in other class?
$liveresellerdb=new Database('host','user','spswd','db');
$fetch = $liveresellerdb->getResult($select_resellerData);
How should I include the database object in my one class?
Class one
{
function a (){
$sql="select * from table ";
//how should i execute here my query i mean to say
//every time i can't create the new object
// i want to know the good method by which i just execute the query by
// giving the database name
}
}
I'd advise against the Singleton pattern (using static members is a variation of this pattern) and use Dependency Injection instead. This means that you pass the database object to your service (the class that uses the connection) through the constructor.
Here is an example.
class UserFinder
{
private $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function findAllActive()
{
$sql = 'SELECT * FROM users WHERE active = 1';
return $this->db->executeAndFetchAll($sql);
}
}
$db = new Database($host, ...);
$finder = new UserFinder($db);
$users = $finder->findAllActive();
This ensures that you are not bound to a specific implementation of the Database class (you could make a sub-class) and will allow you to create separate UserFinders with separate Database instances. It will also make it easier to write tests for your application because you have less dependencies, which are not hidden and also replaceable.
In short: Use dependency injection.
Since global variables are dirty (you always need the global $var; statement), the easiest solution is to store them in a static member of a class, e.g. Database::$db.
Another solution (in a proper OOP environment) would be passing the database instance to the classes - in your code it would be the constructor of one which accepted the instance and then stored in a private member variable.
Maybe, you should think about implementing your Database class according to a Singleton Pattern.
Updated (according to comment below):
Ok. I have only one suggestion here (except passing object via method's parameters and Dependency Injection, described in igorw's comment)...
Dependency Injection is a good way, but this case you - I suppose - have some small amount of databases, so it can be better to save them all in some static private array and get by keys.
So you will have only one public static method getInstance($key) and keys can be stored as some predefined constants (to avoid "spelling" errors).
This way you don't require initialization at all (getInstance($key) can create new Database objects with necessary parameters [passed to constructor] depending on the $key parameter). Dependency Injection looks better in general, but in some particular cases this way can be easier-to-use.
Could be ok to have a Db setAdapter method that store database connections in a static property by name:
Db::setAdapter('db1', 'mysql:host=localhost;dbname=' . $dbname, $user, $pass);
Db::setAdapter('db2', 'mysql:host=localhost;dbname=' . $dbname2, $user2, $pass2);
Then a getAdapter method that will return a database connection when needed:
Db::getAdapter(); // return the default one
Db::getAdapter('db2'); // return an instance by its name
Behind the scenes you could implement a lazy connection too.