I think the title is right but please correct me if It is mis-leading.
The problem: I have a class which wants to use the DB class, now instead of having to "global $db;" in every method I wish to use the DB object I want to be able to place the object reference in my class properties.
Still following? OK here goes:
class user
{
private $id = 0;
private $name = NULL;
private $password = NULL;
private $db;
function __construct()
{
$this->load_db();
}
private function load_db()
{
global $db;
$this->$db =& $db;
}
I get an error "Object of class db could not be converted to string" which is annoying as I can't figure out how to set the var type in PHP...
Now my question is two fold:
1) How do I fix this.
or
2) Is there a better way of doing it as this feels really "kack-handed".
Thanks in advance,
Dorjan
edit: Just to make sure I'm clear I do not want to make multiple instances of the same DB object. At least I believe this to be a good practice ^,^
If you're using $this, you only need one dollar sign. So $this->db.
private function load_db()
{
global $db;
$this->db =& $db;
}
Also if you are using php 5 you dont need to use the =& operator because objects are implicitly passed by reference. Secondly, you should inject $db into the constructor or fetch it from a Registry object instead of using global.
You should better do
class User
{
private $id = 0;
private $name = NULL;
private $password = NULL;
private $db;
function __construct($db=null)
{
$this->db = $db;
}
}
Note that you don't put a $ before variable names if you access properties via $object->. That is were the error comes from.
To use a global inside a class method is really bad practice as you somehow tie your class to that global variable. Better pass it as a parameter to the constructor or a method.
Later you can instantiate the class with
$user = new User($db)
Also note that class names by convention start with a capital letter.
This:
$this->db
Inject the db instance through the constructor
public function __construct($db)
{
$this->db = $db;
}
Yopu'll want to use something called dependency injection. This is where you "inject" an object into another object to do whatever it is the object does. In this case do database stuff
class user
{
private $id = 0;
private $name = NULL;
private $password = NULL;
private $db;
function __construct($database_object)
{
$this->load_db();
$this->$db = $database_object;
}
public function do_db_stuff()
{
$this->$db->doStuff();
}
$db = new Mysql()
$user = new User($db);
$user->do_db_stuff();
Related
I created a simple database connection class:
class db {
private $db_host = "host";
private $db_user = "user";
private $db_pass = "pass";
private $db_name = "db_name";
public $con;
public function __construct() {
$this->con = mysqli_connect($this->db_host, ... );
...
}
public function query($query) {
return mysqli_query($this->con,$query);
}
}
Now, I would like to use $db->query() within another class instance:
class display {
public function menu() {
this function creates a list based on a result of $db->query('SQL query')
}
plus various other functions to display different things, all using $db->query()
So what is the problem?
First, I got this working by adding 'global $db' to $disply->menu() but this is obviously a big NO NO and needs to be specified within each method.
It is probably clear now that I would like to use $db->query(SQL query) wherever and whenever I need an SQL result, not just within the global scope.
I spent the last couple of hours looking this up but to my surprise most people ask how to use something like $instance->instance->method in global.
Many thanks for your time.
Tom
A simple solution is to inject the $db object when you instance your classes
class Display {
protected $db;
public function __construct($db) {
$this->db = $db;
}
public function menu() {
// here you can use $this->db as if it was the global $db;
}
}
You need to add $db as a parameter everytime you instance your classes
$mydisplay = new Display($db);
There are other ways to achieve the same purpose. For example you can make the $db class a singleton, and add a static method to retrieve the instance from wherever you need. And there are more sophisticated ways such as using pimple to manage your dependency injections as a provider instead of doing it manually.
Im trying to understand objects & classes. But Im having a problem. Im trying to pass a variable from a class into another class.
Why Im doing this is mostly because I want to understand more how classs work but also for future where Im gonna need to send database connection into classes.
Here is my code simplified for the problem:
class databaseConnection
{
public function connect(){
return "localhost";
}
}
class like
{
private $database;
public function __construct(){
$this->database = databaseConnection::connect();
}
public function addLike()
{
return $database;
}
}
$obj = new like;
echo $obj->addLike();
But this doesn't show anything. What i thought the results would be is echo "localhost";
Why isn't this working?
connect is not a static method, you should either change it to static or create an instance.
// if you use databaseConnection::connect();
public static function connect(){
or
$db = new databaseConnection;
$this->database = $db->connect();
And you also need to change
public function addLike()
{
// use $this to access object property
return $this->database;
}
You are calling databaseConnection::connect() as a static method. Modify it to:
public static function connect(){ }
Edit - as #Shankar Damodaran pointed, also add:
public function addLike()
{
return $this->database;
}
First of all you should really follow convention and start naming classes StartingWithCapitalLetter.
Secondly, "::" operator is used to call static methods (to put it simply - you don't have to create object of a class to call them, if they are public).
Normally, to call object's method you use operator "->", like $object->method(arguments);
So in your case, you need to first create an object of your databaseConnection class (because you can't call methods on not-initialized methods) and then call "connect" on it, like that:
$connection = new databaseConnection();
$database = $connection->connect();
To pass a parameter, you need to modify the method declaration
public function connect($parameter){
return "Connecting to " ... $parameter;
}
and call it with
$database = $connection->connect($parameter);
On a sidenote, you should really use parenthesis when creating objects of a class, like:
$obj = new like();
echo $obj->addLike();
Also, as deceze pointed out, you need to access class variable using $this instead of accessing local method variable:
public function addLike()
{
return $this->database;
}
public function addLike()
{
return $this->database;
}
$database and $this->database are two different variables. $database is a local function variable which does not exist, it's not the object property you set before.
I am building an API in PHP and I have a question. I'm using classes, and some of these classes need to access my database. However, I don't want to define variables for the database in every single class in order to open it, or have to send my mysqli object as a parameter of every single class constructor.
What would be the best way to go about this? Do I define a global variable of some kind?
A classic solution would be as follows
Create an instance of dbatabase handler class, either raw mysqli (worse) or better abstraction class (way better)
In the constructor of your application class take this db class instance as a parameter and assign it to a local variable
Use this variable with your class.
A quick example:
class Foo()
{
protected $db;
function __construct($db);
{
$this->db = $db;
}
function getBar($id)
{
return $this->db->getOne("SELECT * FROM bar WHERE id=?i", $id);
}
}
$db = new safeMysql();
$foo = new Foo($db);
$bar = $foo->getBar($_GET['id']);
How about using a static classes?
class mysqli_wrapper {
private static $db = null;
public static function open() {
GLOBAL $opts; // this can be global or setup in other ways
if (!self::$db) {
self::close();
self::$db = null;
}
self::$db = #mysqli_connect('p:'.$opts['hn'], $opts['un'], $opts['pw'], $opts['db']);
return self::$db;
}
public static function query($qry) {
return mysqli_query ( self::$db, $qry );
}
public static function affected_rows() { return #mysqli_affected_rows(self::$db); }
public static function error() { return #mysqli_error(self::$db); }
public static function close() { #mysqli_close(self::$db); }
} // end mysqli_wrapper
mysqli_wrapper::open(); // Here's how to call it
In a system I maintain my app needs to access its own MySQL db, as well as remote Oracle and SQL Server databases, and I use a trait for it. Here's a simplification of my code, just using MySQL:
dbaccess.php
trait DatabaseAccess {
protected $db;
private $host = 'host', $dbName = 'db', $username = 'username', $password = 'pword';
public function connectToMysql() {
$this->db= new mysqli(......);
}
}
then in myclass.php
require 'dbaccess.php';
class MyClass {
use DatabaseAccess;
//class code.....
}
All elements of DatabaseAccess will be available as if you hand-typed them in MyClass.
Note: if you're using PHP < 5.4, then this solution won't be possible.
I still have not been able to figure this out. How can we access a one class object in another class?
I am using the below code but I am getting and error:
class ListofRecord{
var $db;
function __construct(){
$db = global $db;
}
function record(){
$record = $this->db->SelectQuery("SELECT * FROM user order by UID ASC");
return $record;
}
}
You need to refer to the global $db variable first and then use it in a statement. You also have a minor syntax error in your constructor. You forgot to use the $this keyword when referring your your $db property.
function __construct(){
global $db
$this->db = $db;
}
It also is a better practice not to use global variables and instead pass any variables that you need as parameters to your method call. In this case it is your constructor:
function __construct($db){
$this->db = $db;
}
$list_of_record = ListofRecord($db);
I've trying to learn PHP OOP and have made some research on how to make a global database class to use around in my project. From what I've seen the most appropriate pattern available is a singleton which would ensure that only one database connection are present at all times. However as this is my first time working with the Singleton pattern, I am not sure that I have made it right.
Is this a proper singleton? Will this code ensure one database connection only? Is there any way I can test this? (Learn a man to fish and he will have food for the rest of his life...)
I am using redbean as my ORM and here's how I set it up plainly:
require_once PLUGINPATH.'rb.php';
$redbean= R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
I've made the following script based upon this source, as my own singleton Database class;
class database {
private $connection = null;
private function __construct(){
require_once PLUGINPATH.'rb.php';
$this->connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
}
public static function get() {
static $db = null;
if ( $db === null )
$db = new database();
return $db;
}
public function connection() {
return $this->connection;
}
}
Thanks!
The instance variable needs to be a static member of the class. I haven't tested this code, but it should work. Connection should probably be static too. With this code, you will have one instance of your database class, and one instance of the connection. It is possible to do this without connection being static, but making it static will ensure there is only one connection instance. I also changed the literal names of the class to php magic constants. This make your code more maintainable. If you change the name of your class down the road, you won't have to go and find all of the literal instances of the old class name in your code. This may seem like overkill now, but trust me, as you work on more and more complex projects, you will appreciate the value.
class database {
private static $connection = null;
private static $db;
private function __construct(){
require_once PLUGINPATH.'rb.php';
self::$connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
}
public static function get() {
if ( !(self::$db instanceof __CLASS__) ) {
$klass = __CLASS__; // have to set this to a var, cant use the constant with "new"
self::$db = new $klass();
}
return self::$db;
}
public function connection() {
return self::$connection;
}
}
You're singleton is almost correct.
The private member (no pun intended) $connection needs to be static as well. You might go with the following too:
class database {
private static $instance = NULL;
protected $conn;
private function __construct() {
$this->conn = mysql_connect( ... );
}
public static function init() {
if (NULL !== self::$instance)
throw new SingletonException();
self::$instance = new database();
}
public static function get_handle() {
if (NULL === self::$instance)
; // error handling here
return self::$instance->conn;
}
}