I am fairly new to object oriented programming. I made this class which connects to mysql database to be called from models. Is there any way i can include 'database.class.php'(my db class file)
in index.php, make it global and then access it from any object like so
$object = new object;
$object->dofunc();
Also another question is dofunc() expects an array for argument, how do i make this array also global so it can be accessed from ANY where!
Here is my db class
<?php
class Database {
private $db;
public function connect($config) {
if (is_array($config)) {
extract($config);
$db = mysqli_connect($host, $username, $password);
if ($db) {
echo "balbabla";
if (mysqli_select_db($db, $database)) {
}
else {
throw new exception("<br/><strong>Could not connect to $database under $host</strong>");
}
}
else {
throw new exception("<br/><strong>Could not connect to mySQL database! Please check your details</stromg>");
}
}
}
}
?>
Also this is the file that contains the array
<?php
//Configuration for the MVC Framework
$_SETTINGS = array();
//Routing settings!
//Default controller(This controller will be loaded if there is none mentioned in the URI)
$_SETTINGS['default_controller'] = 'User';
//Default method(This will be the default method run if no method is mentioned in the URI)
$_SETTINGS['default_method'] = 'Register';
//Database settings
$DB_SETTINGS['host'] = 'localhost';
$DB_SETTINGS['username'] = 'root';
$DB_SETTINGS['password'] = 'foobar';
$DB_SETTINGS['database'] = 'freelance';
?>
Thanks in advance
Is there any way i can include 'database.class.php'(my db class file) in index.php, make it global
You can, but you shouldn't.
Also another question is dofunc() expects an array for argument, how do i make this array also global so it can be accessed from ANY where!
Again you shouldn't.
Dependency injection is the way to go.
To access a global variable from within a function, use the global keyword. For example, to access $DB_SETTINGS from Database::connect(), you could do:
public function connect() {
global $DB_SETTINGS;
...
The array would then be accessible inside that function.
As for globally accessible classes, they are automatically just that. Defining a class makes it available anywhere.
Related
I am looking into oop to enhance my web dev knowledge. At the moment i am having a bit of an issue. I have created a Database class that contains all the queries etc. ( fetch, count, etc. ) This just allows the queries or updates to take up less space in the other classes etc. The issue i am having is passing this class along and making it globally accessible. I have used
global $db;
within a class function but i read that it is bad practice to use that. I also do not want to pass the $db variable as a parameter if i did i would have to change a lot of my current classes and it would just be easier if i can make $db globally available in a "good" practice way.
I can provide my Database class if necessary it is just a simple class with the variable that initiates the connection through construct.
( Second Question )
I was also reading about the singleton instance function, before implementing i read that it was also considered bad practice. Is there something that should take its place?
( I decided to place the class below )
class Database {
private $host = 'localhost';
private $user = 'xxx';
private $pass = 'xxxx';
private $dbname = 'xxxxx';
private $dbh;
private $error;
public function __construct(){
// Set DSN
$dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;
// Set options
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING,
PDO::ATTR_EMULATE_PREPARES => false
);
// Create PDO Instance
$this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
}
public function fetch($sql, $param = "") {
$this->stmt = $this->dbh->prepare($sql);
if (empty($param)) {
$this->stmt->execute();
} else {
$this->stmt->execute($param);
}
return $this->stmt->fetch();
}
}
$db = new Database();
An example of what i am attempting to accomplish is as follows
( User Profile Page )
class User {
function set_user($input) {
if (is_numeric($input)) {
$this->user = $input;
} else {
$user = $db->fetch("SELECT userid FROM users WHERE url=:url", array(':url' => $input));
$this->user = $user['userid'];
}
}
}
AN issue with your approach is not the global var, but that the DB connection is permanently open. It is not always good. This is kind of service object and it is not partiularily bad to have it globally visible.
If you don't want it global and want to solve the open connection issue, you can easily close the connection in the destructor, remove the global var and create/use/delete the DB wherever required.
Another approach would be not to use singleton, but so called service class. Make DB class not instanciable, but rather define service methods (all static) - open, close, execute, or whatever. Than the DB clients should not create DB object, but only access the static methods. This approach fits the reality very nice, as DB-access is seen as a service.
I am learning PHP and trying to wrap my head around both PHP and OOP. I've created this function to allow me to select which database to connect to and then create an object. I want to then use that object outside of the function to run queries, but I'm not quite sure how to do this. Here's what I've got:
function connectToDB($database) {
switch($database) {
case 'DB1':
$host = DB1_HOST;
$user = DB1_USER;
$pw = DB1_PW;
$dbname = DB1_NAME;
$port = DB1_PORT;
break;
case 'DB2':
$host = DB2_HOST;
$user = DB2_USER;
$pw = DB2_PW;
$dbname = DB2_NAME;
$port = DB2_PORT;
break;
}
$db = new MySQLi;
$db->connect($host, $user, $pw, $dbname, $port);
return $db;
}
So what I'm trying to do is tell the function to either connect to 'DB1' or 'DB2', create a MySQLi object and make a database connection for that database, and then give me back the object ($db) so that I can do other things with it outside of the function, but I can't figure out how to get $db to exist outside of this function.
You could do this:
$dbObj = connectToDB('DB1');
$dbObj->someFunction();
The function ConnectToDB() returns an instance of MySQLi. You have to assign the returned instance to a variable. This can be done by doing:
$my_object = connectToDB('DB1') //in case of DB1
Then you can simply call the methods defined on the object in the following way:
$my_object->method_to_call();
In other words, you let a specific instance of a certain class (MySQLi) do some action, method_to_call() in this case.
There are several methods you could use. The one you are using should work as long as you are assigning the returned object to a variable. Another method would be to create the object somewhere else in a higher level class and then use the object variable in the connection method (this code probably doesn't work, it's just to illustrate the concept).
// declare database connection variable outside of functions in class
private $db;
...
function init() {
...
$this->db = new MySQLi; // or call this inside the connection function
}
function connectToDB($database) {
$this->db->connect($host, $user, $pw, $dbname, $port);
}
Another method would be to pass the object in by reference to the function:
$db = new MySQLi;
function connectToDB($database, &$db) {
// the & in front of the param indicates that it is passing in the original object by reference instead of making a copy in the local scope.
$db->connect($host, $user, $pw, $dbname, $port);
// since the object is passed in by reference, we don't need to return it
}
My database class works perfectly and I call it like this $db = new Database('user', 'pass', 'db', 'host');. I top of my script I am defining this database, but later in the script I am trying to use the connection inside a function, but it seems to that the $db is not global, so my function can't access it. I have the possibility to create a new database class connection inside every function in my script, but I really would like to access the $db as a global access point.
Here is some code:
require_once('database_class.php');
$db = new Database('user', 'pass', 'db', 'host');
// I can reach the $db here and make the $db->PDO->'statement'();
function userExists($user) {
$bool = false;
// But in here I can't access $db...
$query = $db->PDO->query('SELECT * FROM login WHERE username = "$user"');
$result = $query->fetch();
if ($result) {
// User exists
$bool = true;
}
return $bool;
}
Put global $db at the beginning of the function like so:
function userExists($user) {
global $db;
// Rest of code here
Variables within functions only exist locally by default in PHP. To use a variable declared outside of a function which is not passed as an argument (e.g $user) you need to use a global variable as shown above.
You could probably just modify your functions to take the $db var as an argument. e.g. :
function userExists($user, $db) {
...
}
Objects are passed by reference by default (see here) so you won't be inadvertently making copies of the $db object with each call.
I use classes for connections and queries too. But it would help that you define already in your class the variables needed for connection, so you don't have to repeat them in every page of code.
and maybe this? use the db as an argument.
function userExists($user, $db) { //codecodecode }
I have config.php with this...
$dbhost = "localhost";
I want to be able to use the $dbhost variable inside a class.
User.class.php
include 'config.php';
class User {
private $dbhost = ???
}
There's a couple other questions like this, but they were for some other specific uses, and I guess it's just a basic thing that I can't really find anything else about it on the web.
UPDATE: Wow, thanks for all the help everybody. New to this site, but I might just stick around and give back where I can.
You could use a global variable, defining a constant would be better, but using a setter/getter method is best. When you are using a class, any outside resource that it uses should be passed to it. This design patter is called dependency injection if you want to research it further.
In this example, I've combined the setter and getter into a single method, and included the ability to set the value when you first create the instance, using a constructor:
class User
{
private $host = null;
public function host($newHost = null)
{
if($newHost === null)
{
return $this->host;
}
else
{
$this->host = $newHost;
}
}
function __construct($newHost = null)
{
if($newHost !== null)
{
$this->host($newHost);
}
}
}
//Create an instance of User with no default host.
$user = new User();
//This will echo a blank line because the host was never set and is null.
echo '$user->host: "'.$user->host()."\"<br>\n";
//Set the host to "localhost".
$user->host('localhost');
//This will echo the current value of "localhost".
echo '$user->host: "'.$user->host()."\"<br>\n";
//Create a second instance of User with a default host of "dbserver.com".
$user2 = new User('dbserver.com');
//This will echo the current value of "dbserver.com".
echo '$user2->host: "'.$user2->host()."\"<br>\n";
For something like a db host, use a constant:
// define it first
define('DBHOST', 'localhost');
// then anywhere you can use DBHOST:
class User {
function __construct() {
echo DBHOST;
}
}
http://php.net/manual/en/language.constants.php
several ways I think.
First pass it to the class constructor:
include 'config.php';
class User {
private $dbhost;
function __construct($dbhost){
$this->dbhost=$dbhost;
}
}
$user= new User($dbhost);
Or use a setter:
include 'config.php';
class User {
private $dbhost;
function setDbhost($dbhost){
$this->dbhost=$dbhost;
}
}
$user= new User();
$user->setDbhost($dbhost);
Or using CONSTANTS:
define('DBHOST', 'localhost');
class User {
private $dbhost;
function __construct(){
$this->dbhost=DBHOST;
}
}
OR using global:
include 'config.php';
class User {
private $dbhost;
public function __construct() {
global $dbhost;
$this->dbhost=$dbhost;
}
}
If you are planning to use variables (and not constants), then use the following code.
In config.php
$dbhost = "localhost";
In User.class.php
include 'config.php';
class User {
global $dbhost;
}
I am confused on how to handle the logic of reusing the database object and configuration variables or constants that stands global for the application.
the way i have been doing till now is, i created a config.php file in Config directory and declare all the config elements for example my typical config.php file would look like this.
#Start Session
session_start();
#Start Output Buffering
ob_start();
#Set Default TimeZone
date_default_timezone_set('Asia/Kolkata');
#Define Time Constant
define('DATE', date("d-F-Y/H:ia"));
#Define Paths
define('CLASSES',$_SERVER['DOCUMENT_ROOT'].'/resources/library/classes/');
define('MODELS',$_SERVER['DOCUMENT_ROOT'].'/resources/library/models/');
define('LOGS',$_SERVER['DOCUMENT_ROOT'].'/resources/logs/');
#Define Connection Constant
define('HOST','localhost');
define('USERNAME','username');
define('PASSWORD','password');
define('DATABASE','dbname');
try
{
#Connection String.
$dbh = new PDO('mysql:host='.HOST.';dbname='.DATABASE,USERNAME,PASSWORD);
#Set Error Mode to ERRMODE_EXCEPTION.
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
#Print Errors.
echo $e->getMessage();
#Log Errors into a file
file_put_contents(LOGS.'Connection-log.txt', DATE.PHP_EOL.$e->getMessage().PHP_EOL.PHP_EOL, FILE_APPEND);
}
#Autoload Classes.
function __autoload($class) {
require_once CLASSES.'class.'.strtolower($class).'.php';
}
and in index.php file i would include this file once and re-use it in every object.
my index.php typically consist of controllers like this.
if(isset($_GET['users'])) {
require_once(MODELS.'users/users.php');
} else if(isset($_GET['categories'])) {
require_once(MODELS.'categories/categories.php');
} else if(isset($_GET['search'])) {
require_once(MODELS.'search/search.php');
}
and in Models i would instantiate the object i want and use it for example in users/users.php i would instantiate it like this
$user = new User($dbh);
all is working fine but the problem is for each and every class i have to pass the database handle object through constructor and re-use it in the class which is kind of ugly for me. and this approach creates a problem for me if i want to use class which contains static methods and properties that holds the Application settings that is to be retrieved from database. my requirement is such that.
I want to create a static method using singleton pattern that will hold the database object that is to be used across the application without the need to pass the the $dbh object each and everytime through constructor for each and every class. and i am very much confused on how should i deal with this.
thank you
I have a similar design pattern where I connect and store the connection in a global.
You do not need to pass the database variable to every class as it is a global.
You can use it anywhere like this:
$GLOBALS['dbh'];
To hide this I have actually created a function named get_db_connection() which first checks if there is a valid connection in the $GLOBALS array and then returns it. Also if there is no valid connection there, it creates a new connection stores it in the $GLOBALS and returns it.
It has the added benifit that I do need to instantiate the connection manually anywhere, it is automatically created on the first call to get_db_connection and is available everywhere subsequently.
The get_db_connection function looks something like this:
function get_db_connection(){
if(isset($GLOBALS['db_conn']) && get_class($GLOBALS['db_conn']) == 'PDO'){
return $GLOBALS['db_conn'];
}else{
$conn = new PDO(/* parameters */);
$GLOBALS['db_conn'] = &$conn;
return $conn;
}
}
defence in favour of global
I consider this to be an excusable usage of globals for following reasons:
The variable $dbh is already a global as it is not inside a function
or a class.
You are not accessing the global directly anywhere in
your program, but only through a single function get_db_connection
so the problem that anyone can change the value of the global is not
here.
The only way around this is by using a Singleton, which may be
unnecessary for such a simple problem.
Of these I consider the 2nd reason to be most concrete.
here is what i came up with finally.
class DB {
protected static $_dbh;
const HOST = 'localhost';
const DATABASE = 'dbname';
const USERNAME = 'usname';
const PASSWORD = 'passwo';
private function __construct() { }
public static function get_db_connection() {
if(!isset(self::$_dbh)) {
self::$_dbh = new PDO('mysql:host='.self::HOST.';dbname='.self::DATABASE,self::USERNAME,self::PASSWORD);
self::$_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$_dbh;
}
}
Applying singleton pattern and with static method call i can easily access the database object without passing the database object through class constructor.
To call the database object within or outside the class scope all i have to do is call a single line of code.
DB::get_db_connection();
this sounds more feasible isn't it? :)
You could try something like this:
function cnn() {
static $pdo;
if(!isset($pdo)) {
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_TIMEOUT, 30);
$pdo->setAttribute(PDO::ATTR_PERSISTENT, true);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
return $pdo;
} else {
return $pdo;
}
}
After that, you can call any queries you want:
echo cnn()->query('SELECT firstname FROM user WHERE id=4;')->fetch(PDO::FETCH_COLUMN)
Second query (object is reused)
echo cnn()->query('SELECT title FROM news WHERE id=516;')->fetch(PDO::FETCH_COLUMN)