I have database credential variables from a file, named config.php :
$db_server = 'localhost';
$db_user = 'username';
$db_password = 'secret'
$db_name = 'dbname';
now, I have a PHP class under /class folder and it works perfectly fine for CRUD process. named MysqlCrud.class.php :
class Database {
private $db_host = 'localhost'; // Change as required
private $db_user = 'username'; // Change as required
private $db_pass = 'secret'; // Change as required
private $db_name = 'dbname'; // Change as required
}
but, I want to use centralised variables from config.php. that's why I add some lines like this :
include('../config.php');
class Database {
global $db_server;
global $db_user;
global $db_password;
global $db_name;
private $db_host = $db_server; // Change as required
private $db_user = $db_user; // Change as required
private $db_pass = $db_password; // Change as required
private $db_name = $db_name; // Change as required
}
but, I got this following error message :
Parse error: syntax error, unexpected 'global' (T_GLOBAL), expecting function (T_FUNCTION) in /home/*** on line **
why I can't use variables from config.php file inside Database class? what did I do wrong here? thank you.
The problem with the approach you've chosen to use is that the class is no longer reusable. Any time you instantiate the Database class, it will use the global variables.
I'd be more inclined to set it up like this:
Database.php
class Database {
private $host;
private $db_name;
private $username;
private $password;
function __construct($host, $db_name, $username, $password) {
$this->host = $host;
$this->db_name = $db_name;
$this->username = $username;
$this->password = $password;
}
}
Then in the file you use the Database class:
include('../config.php');
$db = new Database($db_server, $db_name, $db_user, $db_password);
Maybe you can try it like this:
function connDB()
{
$conn=mysql_connect("localhost", "root", "") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());
return $conn;
};
Put this function in your config file or another file such as globalFunctions.php (which contains every general function you need). Just call this function everytime you need it.
Inside a class you can ONLY have member declaration. Global variables are NOT class members, therefore you can't have them inside the class. But you can have them inside methods.
class Database {
private $db_host;
//... the rest of them here
//class constructor. Gets called every time you create an instance of this class.
function __construct() {
global $db_server;
global $db_user;
global $db_password;
global $db_name;
$this->db_host = $db_server;
//.... you get the idea
}
}
Edit 2017-07-11:
Don't do this. Don't use global variables. They are easy to overwrite somewhere and you'd end up debugging a lot. Plus requiring the global keyword is dirty. A proper partial solution is provided by #br3nt. But it still uses global variables and initializes the $db variable in a global scope.
If you have access to the site config in Apache for example, for that website, you can use mod_env to set configuration in environment variables. Example:
<VirtualHost *:80>
.....
SetEnv DB_USER=myDatabaseUser
SetEnv DB_PASSWORD=12345
...
</VietualHost>
And then you can read this in PHP with getEnv('DB_USER') http://php.net/manual/en/function.getenv.php
Another option is to make your config return an array:
config.php
<?php
return [
'db_user'=>'myDbUser,
'db_password'=>'12345'
];
And you should have a single point of entry that ensures read-only access to that config.
Config.class.php
<?php
class Config {
private $_config;
public function __construct() {
$this->_config = include('path/to/config.php');
}
public function __get($key) {
if(isset($this->_config[$key])) {
return $this->_config[$key];
}
return null;
}
}
usage:
$config = new Config();
$dbUser = $config->db_user;
$dbPassword = $config->db_password;
Edit 2, same day
Why are globals bad?
Having global variables is nice because you can access them everywhere, right? Is it also a good practice to have all class members as public? No. Let's say you have a global variable used in many places. Someone accidentally writes this:
if($myGlobalVariable='something') { ... }
And his code works with just a weird bug that nobody cares about. But your code breaks because you actually depend on the exact value of $myGlobalVariable. And you look at the config, and see that it's the right value, and then scratch your head.
This is just one case. Unhindered read+write access to shared resources can be dangerous. It's easy to override, and no error will be output. It also pollutes the global space.
It's also a code smell if you have global functions in a config file. Think of config files as static text files that shouldn't even contain code. The only reason they're PHP files is because of speed, ease, and harder to break security that way.
Here is an option to set your class members to a global value using __construct()
include('../config.php');
class Foo {
private $db_host;
private $db_user;
private $db_pass;
private $db_name;
public function __construct() {
global $db_server;
global $db_user;
global $db_password;
global $db_name;
$this->db_host = &$db_server; // Change as required
$this->db_user = &$db_user; // Change as required
$this->db_pass = &$db_password; // Change as required
$this->db_name = &$db_name; // Change as required
}
}
Since we are using Assignment by Reference the inner class members are the same variables as the global ones (thus change as required).
Also if you want to avoid writing global you can use the reserved variable $GLOBALS, which as described in the documentation is:
An associative array containing references to all variables which are currently defined in the global scope of the script. The variable names are the keys of the array.
So your code could became something like this:
$GLOBALS = array(
'DB_HOST' => 'localhost',
'DB_USER' => 'user',
'DB_PASS' => 'secret',
'DB_NAME' => 'my_db'
);
class Foo {
private $db_host;
private $db_user;
private $db_pass;
private $db_name;
public function __construct() {
$this->db_host = &$GLOBALS['DB_HOST']; // Change as required
$this->db_user = &$GLOBALS['DB_USER']; // Change as required
$this->db_pass = &$GLOBALS['DB_PASS']; // Change as required
$this->db_name = &$GLOBALS['DB_NAME']; // Change as required
}
}
Related
class global_class extends Timemine
{
private $DBPrefix = '';
public function __construct()
{
global $DBPrefix;
// Load settings
self::loadsettings();
$this->database = $db;
$this->DBPrefix = $DBPrefix;
.
.
$DBPrefix is declared outside as a private but inside the function its redeclared? as global.
Is this correct?
Thank you.
$DBPrefix is actually not redeclared. There are two versions of the variable. The first one (private $DBPrefix = '';) is a member variable, the second one (global $DBPrefix) is a local scope variable of the constructor (which refers to a third global version of the variable, but let's leave this aside). See the PHP docs about variable scope for more information
The value of the member variable is then set to the same value as the local scope variable with this line: $this->DBPrefix = $DBPrefix; So after this line both versions have the same value. Technically, your code is correct.
However, using globalis usually bad. It is probably better to pass $DBPrefix in the constructor like:
public function __construct($DBPrefix) {
// Load settings
self::loadsettings();
$this->database = $db;
$this->DBPrefix = $DBPrefix;
}
In my config.php file I have a variable that is set to 'localhost'.
$CONFIG['MySQLi']['host'] = "localhost";
However, when I include this config.php in my database class, I test it by calling the variable in an echo through the __construct() method
public function __construct() {
echo $CONFIG['MySQLi']['host'];
}
But then for some reason, I get this error:
Notice: Undefined variable: CONFIG in C:\xampp\htdocs\Muse\classes\class.database.php on line 15
However I get no errors for importing the config.php file. Would someone be able to explain why this is happening? Thankyou
The function doesn't know about variables that were defined outside due to variable scope.
public function __construct() {
global $CONFIG;
}
should resolve this. However, this is usually considered bad practice.
Alternatively you can use static attributes as shown by Kohjah Breese, pass the config array to the constructor (as suggested by AlexP) or use a construct like the following.
/config/mysqli.php
<?php
return array(
//what now is $CONFIG['MySQLi']
);
and in the function
public function __construct() {
$config = include '/config/mysqli.php';
}
For anybody who still wants the answer to this question, another good way to do it is by DEFINING a variable.
define('VARIABLE', 'VALUE');
And then call it by doing VARIABLE. E.g.
<?php echo VARIABLE; ?>
AS above, function do not have access to standard variables stored outside of them, but a better solution is to create a class you want to store global variables in. I use something like this:
class Conf
{
// Project
static $CODE = 'F';
static $NAME = 'For';
static $ACCESS = 'public';
static $CHARSET = 'utf-8';
static $DATA = array();
static $CACHE = false;
static $HTMLINDENT = true;
// Diagnostic
static $SHOWEXECTIME = true;
// Paths
static $PATH_FILESYSTEM = '';
static $PATH_CORE = '/var/www/sites/core';
static $PATH_DOMAIN = 'localhost';
static $PATH_URL = 'http://localhost/sites/for/';
static $PATH_CACHE = 'cache/';
static $PATH_CSS = 'css/';
static $PATH_DATA = 'data/';
static $PATH_JS = 'js/';
static $PATH_LOG = 'logs/';
static $PATH_XML = 'xml/';
static $PATH_XSL = 'xsl/';
// DB Details
static $DB_USER = 'root';
static $DB_PASS = 'pass';
static $DB_DSN = 'mysql:host=localhost;dbname=for;charset=utf8';
}
My tests showed this to be the quickest solution. Some people use constants, which are very slow. Globals have been depreciated, and are a security risk.
You can access any of these vars from anywhere in PHP using Conf::$NAME; etc.
I'm new to OOP. Originally I was defining variables and assigning values to them within the class and outside of the constructor, but after an OOP lesson in Java today, I was told this is bad style and should be avoided.
Here is my original PHP database connection class that I mocked-up:
class DatabaseConnection {
private $dbHost = "localhost";
private $dbUser = "root";
private $dbPass = "";
private $dbName = "test";
function __construct() {
$connection = mysql_connect($this->dbHost, $this->dbUser, $this->dbPass)
or die("Could not connect to the database:<br />" . mysql_error());
mysql_select_db($this->dbName, $connection)
or die("Database error:<br />" . mysql_error());
}
}
Is the above considered okay? Or is the following a better way?
class DatabaseConnection {
private $dbHost;
private $dbUser;
private $dbPass;
private $dbName;
function __construct() {
$this->dbHost = "localhost";
$this->dbUser = "root";
$this->dbPass = "";
$this->dbName = "test";
$connection = mysql_connect($this->dbHost, $this->dbUser, $this->dbPass)
or die("Could not connect to the database:<br />" . mysql_error());
mysql_select_db($this->dbName, $connection)
or die("Database error:<br />" . mysql_error());
}
}
What should I be focusing on to make sure I am understanding OOP correctly?
First of all: this is pointless.
You are creating an object wrapper for the 10+ year old mysql_* function. This php extension is no longer maintained and the process of deprecation has already begun. You should not use this API for any new projects in 2012.
Instead you should learn how to use PDO or MySQLi and work with prepared statements.
That said .. lets take a look at your code:
Constructor should receive all the parameters required for creating new instance, parameters should not be hard-coded in the class definition. What if you need to work with two databases at the same time ?
When connection is created, it should be stored in object's scope variable. Something along the lines of $this->connection = mysql_conn.... Instead you store it in local variable, which you "loose" right after constructor is done.
You should not use private variables for everything. They are not visible to classes which would extend your original class. Unless it is intentional, you should choose protected for this.
The or die('..') bit most go. Do not stop the whole application if connection fails. Instead you should throw an exception, which then can be handled outside of the constructor.
Well, it's not going to run quite yet. You need to change your variables so that they match your connection params:
$dbHost = "localhost";
Should be
$this->dbHost = 'localhost';
I normally don't put my login params inside of the class at all. I would pass them into the constructor when the object is created. Use an outside config file so you can actually use this class on more than one build. :)
Update::
Okay, so here are a few little OOP configuration gold-nuggets that help you build a dynamic Database class.
Check out http://redbeanphp.com/ It will allow you to do a psuedo ORM style of data modelling. Super easy to install, and ridiculously easy to get your database up and running. http://redbeanphp.com/manual/installing
Create a configuration file that contains things like constants, template setups, common functions, and an AUTOLOADER Configuration files are key when working in version controlled environments. :)
Build your Database class as an abstract class http://php.net/manual/en/language.oop5.abstract.php
abstract class Database
{
public function update()
{
}
public function deactivate()
{
}
public function destroy()
{
}
//etc.
}
class MyAppObject extends Database
{
}
Put all of your class files into a library folder, and then put your configuration file into that library. Now, to make your life easier you can use an autoloader function to bring your classes to life whenever you need them, without having to include any specific class. See below:
//note: this is never explicitly instantiated
//note: name your files like this: MyAppObject.class.php
function my_fancypants_autoloader( $my_class_name )
{
if( preg_match( "%^_(Model_)%", $my_class_name ) ) return;
require_once( "$my_class_name.class.php" );
}
spl_autoload_register( 'my_fancypants_autoloader' );
Now all you have to do is include one configuration file in your .php files to access your classes.
Hope that points you in the right direction! Good luck!
Since your are only using them into the __construct method, you don't need them as class attributes. Only the $connection has to be kept for later use imho.
It might be much much better to not give any default values to those arguments but let them being set from the outside.
$db = new DatabaseConnection("localhost", "user", "password", "db");
They are plenty of PHP tools for that already, find them, read them and learn from that. First of all, use PDO and what is true in Java isn't always true in PHP.
The latter is probably better, but with an adjustment: pass some arguments to the constructor, namely the connection info.
Your first example is only useful if you've got one database connection and only if you're happy hard-coding the connection values (you shouldn't be). The second example, if you add say, a $name parameter as an argument, could be used to connect to multiple databases:
I'm new to OOP. Originally I was defining variables and assigning values to them within the class and outside of the constructor, but after an OOP lesson in Java today, I was told this is bad style and should be avoided.
class DatabaseConnection {
private $dbHost;
private $dbUser;
private $dbPass;
private $dbName;
function __construct($config) {
// Process the config file and dump the variables into $config
$this->dbHost = $config['host'];
$this->dbName = $config['name'];
$this->dbUser = $config['user'];
$this->dbPass = $config['pass'];
$connection = mysql_connect($this->dbHost, $this->dbUser, $this->dbPass)
or die("Could not connect to the database:<br />" . mysql_error());
mysql_select_db($this->dbName, $connection)
or die("Database error:<br />" . mysql_error());
}
}
So using this style, you now have a more useful class.
Here is mine and it works rather well:
class Database
{
private static $_dbUser = 'user';
private static $_dbPass = 'pwd';
private static $_dbDB = 'dbname';
private static $_dbHost = 'localhost';
private static $_connection = NULL;
/**
* Constructor
* prevents new Object creation
*/
private function __construct(){
}
/**
* Get Database connection
*
* #return Mysqli
*/
public static function getConnection() {
if (!self::$_connection) {
self::$_connection = #new mysqli(self::$_dbHost, self::$_dbUser, self::$_dbPass, self::$_dbDB);
if (self::$_connection -> connect_error) {
die('Connect Error: ' . self::$_connection->connect_error);
}
}
return self::$_connection;
}
}
By making the __construct empty, it prevents a new class being instantiated from anywhere. Then, make the function static so now all I need to do to get my connection is Database::getConnection() And this is all in an include file, in a password protected folder on the server and just included with each class file. This will also check to see if a connection is already open before attempting another one. If one is already established, it passes the open connection to the method.
<?php
class config
{
private $host='localhost';
private $username='root';
private $password='';
private $dbname='khandla';
function __construct()
{
if(mysql_connect($this->host,$this->username,$this->password))
{
echo "connection successfully";
}
}
function db()
{
mysql_select_db($this->$dbname);
}
}
$obj=new config();
?>
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;
}
<?php
$settings['hostname'] = '127.0.0.1';
$settings['username'] = 'root';
$settings['password'] = 'root';
$settings['database'] = 'band';
$settings['dbdriver'] = 'mysql';
/**
* DATABASE
*/
class database
{
protected $settings;
function __construct()
{
}
function connect()
{
$this->start = new PDO(
$this->settings['dbdriver'] . ':host='.
$this->settings['hostname'] . ';dbname='.
$this->settings['database'],
$this->settings['username'],
$this->settings['password'],
array(PDO::ATTR_PERSISTENT => true));
$this->start->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
}
}
?>
ok im still a student so today im learning about scope and connections database
the question is how can i put the $settings out of the class in to the protected $settings in class ?
You are already on the right path in the code you show: Don't use public (global) scope at all - it's not regarded good practice in OOP to rely on global variables, because it breaks encapsulation. Instead, inject the settings into the object when initializing it.
You could add a constructor to do that:
function __construct($settings)
{
$this->settings = $settings;
}
and then initialize the class like so:
$database= new database($settings);
or like so, to prevent a variable with sensitive data floating around:
$database= new database(array('hostname' => '127.0.0.1',
'username' => 'root',
'password' => 'root',
'database' => 'band',
'dbdriver' => 'mysql'));
As a side note, in production use, consider deleting the password variable from the array after connecting, for security. It's nothing essential but a nice additional thing to do.
Either pass the $settings as function argument, import it to current scope using global or access via $GLOBALS.
Pass as argument:
public function __construct(array $settings) {
$this->settings = $settings;
}
Import using global:
public function __construct() {
global $settings;
$this->settings = $settings;
}
Use $GLOBALS:
public function __construct() {
$this->settings = $GLOBALS['settings'];
}
I would choose the pass as arg variant. The other versions are only dirty hacks (imho).
A better way would be to either look in a configuration file (a XML file for example) for the configuration, or have the connect() method (or your constructor) called with the desired parameters.