How to access variable outside function without globals variables - php

I have a config.php file with:
$globalConf = array(
'DbConfig' => array(
'Hostname' => 'localhost',
'Username' => 'myuser',
'Password' => 'xxxxxxxx',
'Database' => 'mydb'
)
);
and in other file (this includes the config.php) i have this function:
function db_connect()
{
if (!($db_link = mysqli_connect($globalConf['DbConfig']['Hostname'], $globalConf['DbConfig']['Username'], $globalConf['DbConfig']['Password'], $globalConf['DbConfig']['Database'])))
exit();
return $db_link;
}
This doesn't work. I would need to include the global $globalConf inside the db_connect() function, but I don't want to do this (i have more configurations variables and multiple functions that require those and I don't want to use a global $variable in all functions and subfunctions).
I want to set the $globalConf as a persistent global variable (possibly accesible like class?), for example:
mysqli_connect(myglobal::$globalConf['DbConfig']['Hostname'])
how can do this?
Solved:
class MainConf {
public static $globalConf = array(
'DbConfig' => array(
'Hostname' => 'localhost',
'Username' => 'myuser',
'Password' => 'xxxxxxxx',
'Database' => 'mydb'
)
);
}
and:
function db_connect()
{
if (!($db_link = mysqli_connect(MainConf::$globalConf['DbConfig']['Hostname'], MainConf::$globalConf['DbConfig']['Username'], MainConf::$globalConf['DbConfig']['Password'], MainConf::$globalConf['DbConfig']['Database'])))
exit();
return $db_link;
}

Other than passing the data to the function, which has already been mentioned, you could create a class for your configuration or global data and use a static access method to retrieve them.
<?php
class DbConfig {
private static $data = array(
'Hostname' => 'localhost',
'Username' => 'username',
// ...
);
public static function get($name) {
return array_key_exists($name, self::$data) ? self::$data[$name] : '';
}
}
Then in your your functions you would access it like so
DbConfig::get('Hostname');

Pass data into function using parameters... for example:
function db_connect($dbinfo) {
if (!($db_link = mysqli_connect($dbinfo['Hostname'], $dbinfo['Username'], $dbinfo['Password'], $dbinfo['Database'])))
exit();
return $db_link;
}
and call it like
db_connect($globalConf['DbConfig'])
I think this is the easiest way.
Update
class MainConf {
public $db; // this will get your $globalConf['DbConfig'] array
function __construct($dbinfo) {
$this->db = $dbinfo; // assign it to $db on class construction
}
function db_connect() {
// use it where you want
if (!($db_link = mysqli_connect($this->db['Hostname'], $this->db['Username'], $this->db['Password'], $this->db['Database'])))
exit();
return $db_link;
}
}
Now you can pass your external data into class like this:
$conf = new MainConf($globalConf['DbConfig']);
$dblink = $conf->db_function();
This way you don't have to define your data inside the class. Just pass it as parameter, assign that param to class variable and use these information everywhere you want inside the class.
But I guess you're using these info only for db_connect() so it's not necessary to keep it on global level inside class. If you call that method manually you can add $dbinfo parameter in db_connect() so you don't need __construct() method and your class will look like this
class MainConf {
function db_connect($dbinfo) {
if (!($db_link = mysqli_connect($dbinfo['Hostname'], $dbinfo['Username'], $dbinfo['Password'], $dbinfo['Database'])))
exit();
return $db_link;
}
}
And now call it this way
$conf = new MainConf;
$dblink = $conf->db_connect($globalConf['DbConfig']);
Just choose what the best fits your needs.

Related

Using Namespaces and Databases together

The way I used to use a database would be
class sitedb
{
public $db = '';
public $config;
public $settings = array(
'host' => "localhost",
'database' => "database",
'username' => "user",
'password' => "pass",
);
public function __construct(){
$this->db = new PDO(
"mysql:host={$this->settings['host']};" .
"dbname={$this->settings['database']};" .
"charset=utf8",
"{$this->settings['username']}",
"{$this->settings['password']}"
);
$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
}
}
And then say I have a user script that uses this database
class User {
public function __construct() {
$this->db = new sitedb();
}
}
Now within my code I could use $resource = $this->db->db->prepare($query);
A friend of mine recently suggested I used namespaces instead and it would make things easier than the constructor every time, but not sure how to go about this.
I have my database class file
namespace database;
class site
{
public $db = '';
public $config;
public $settings = array(
'host' => "localhost",
'database' => "database",
'username' => "user",
'password' => "pass",
);
public function __construct(){
$this->db = new PDO(
"mysql:host={$this->settings['host']};" .
"dbname={$this->settings['database']};" .
"charset=utf8",
"{$this->settings['username']}",
"{$this->settings['password']}"
);
$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
}
}
class auth
{
}
My thought process here was that I could use
$resource = \database\site::????
Now I'm at a loss as to how to actually connect. I'm hoping I drew up my issue well enough to show what I'm after. I'm just not sure how I can use this to actually connect to the database.

PHP Aura SQL, swithing database inside class

I am a bit puzzled here, I am easing myself into oop and struggling a little. I have beenusing Aura SQL (php) and have achieved pretty much what I need, but, it has become necessary to connect to more than one DB to update some legacy code I have been passed.
class Core {
public $pdo;
private static $instance;
private function __construct() {
$this->pdo = new ExtendedPdo(
'mysql:host=localhost;charset=utf8;dbname=db',
'user',
'pass'
);
$this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES utf8');
}
public static function getInstance() {
if (!isset(self::$instance)) {
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
}
I have tried to amend by passing the values in via the constructor, but, it seems to be ignored eg:
private function __construct($db_name) {
if !empty($db_name)) { $this->db = $db_name; } else { $this->db = 'default_db'; }
$this->pdo = new ExtendedPdo(
'mysql:host=localhost;charset=utf8;dbname='.$this->db.'',
....
Normally you would use getInstance(); but I have been trying instantiating a new object to access the other databases.
Thanks for any advice.
Please checkout the ConnectionLocator via which you can create default connection, and rest of the connections. Taking code snippet from the readme.
<?php
use Aura\Sql\ConnectionLocator;
use Aura\Sql\ExtendedPdo;
// default connection
$default = function () {
return new ExtendedPdo(
'mysql:host=default.db.localhost;dbname=database',
'username',
'password'
);
};
// read connections
$read = array(
'slave1' => function () {
return new ExtendedPdo(
'mysql:host=slave1.db.localhost;dbname=database',
'username',
'password'
);
},
'slave2' => function () {
return new ExtendedPdo(
'mysql:host=slave2.db.localhost;dbname=database',
'username',
'password'
);
},
'slave3' => function () {
return new ExtendedPdo(
'mysql:host=slave3.db.localhost;dbname=database',
'username',
'password'
);
},
);
// write connection
$write = array(
'master' => function () {
return new ExtendedPdo(
'mysql:host=master.db.localhost;dbname=database',
'username',
'password'
);
},
);
// configure locator at construction time
$connections = new ConnectionLocator($default, $read, $write);
$default_connection = $connections->getDefault();
$read_slave1_connection = $connections->getRead('slave1');
$read_any_connection = $connections->getRead();
$write_connection = $connections->getWrite();

Accessing arrays from within a class

I have a config file that contains an array of settings/parameters. The problem I'm running into is accessing this array from within a class. My first guess was to do something like this.
Settings File:
$config = array (
'db' => array (
'host' => 'localhost',
'password' => 'password',
'port' => 3306,
'database' => 'my_db',
'user' => 'root'
),
'email' => array (
'username' => 'someone#somewhere.com',
'smtp' => 'smtp.somewhere.com',
'ssl' => true,
'password' => 'my_password',
'port' => 587
)
// other stuff
);
The Confiuration class
class CoreConfig
{
static $confArray;
public static function read($name)
{
return self::$confArray[$name];
}
public static function write($name, $value)
{
self::$confArray[$name] = $value;
}
}
And use it like: CoreConfig::write('username', $config['email']['username']);. Example using it in a class:
Usage
class SomeClass {
public function __construct() {}
public function getUserName() {
return CoreConfig::read('username');
}
}
Although this works, it feels like it's considered bad practice. Alternatively I can take the initial $config and load it right away in my $confArray instead "writing", which looks like an ever worse idea. Is there another approach to this?
It sure feels a bit weird to hard code anything in an application, even if you're doing a configuration file. There are many methods for doing what you're trying to do, but the most important thing is to keep all "hard coded" values at the same place.
If you have access to any kind of SQL to do your work, I would recommend to put all configurations values in a data table. Doing this, you avoid having any hard coded values directly in the code, since they're in a database.
Config class
class CoreConfig
{
static $confArray = null;
public static function read($name)
{
if(self::$confArray == null)
self::loadConfig();
return self::$confArray[$name];
}
private static function loadConfig()
{
self::$confArray = DatabaseManager::fetchAll("SELECT * FROM config");
}
}
Database Manager class
class DatabaseManager
{
private static $instance = null;
private static $host = "YOUR HOST NAME HERE";
private static $dbName = "YOUR DATABASE NAME";
private static $dbUser = "YOUR DATABASE USER";
private static $dbPass = "YOUR DATABASE PASSWORD";
private function __construct() {}
private static function getDb()
{
if(is_null(self::$instance))
{
self::$instance = new PDO("mysql:host=" .self::$host. ";dbname=" .self::$dbName, self::$dbUser, self::$dbPass);
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$instance;
}
public static function fetchAll($SQL)
{
$return = null;
try
{
$return = self::getDb()->query($SQL)->fetchAll();
}
catch(Exception $e)
{
// If you want to display errors directly on the page
echo "SQL Query Error<br />";
echo "Request: $SQL<br />";
echo $e->getMessage();
}
return $return;
}
}
You may refer to PDO Documentation on php.net in order to add features to the Database manager. You will have to add more methods if you want to be able to write in the database using PHP.
If you have no database options, then you can use an XML or JSON configuration file and parse it into an array at the moment of reading its values.
Hope this helps!

Declare a global object for multiple functions

So I have a list of functions that i'm using in a web app. Most of the functions however, make calls to a database class. Here are two functions for example:
function add_post($userid,$body,$cat_id,$user_link){ //This function inserts new posts into the db
$db = new MysqliDb('localhost', 'root', 'root', 'my_db');
$now = date("Y-m-d H:i:s");
$insertData = array(
'user_id' => $userid,
'body' => $body,
'stamp' => $now,
'cat_id' => $cat_id,
'link' => $user_link
);
$db->insert('posts', $insertData);
}
function grab_username($userid){ //This function takes a user id, and returns the associated user_name
$db = new MysqliDb('localhost', 'root', 'root', 'my_db');
$params = array($userid);
$results = $db->rawQuery("SELECT username FROM users WHERE id = ?", $params);
//print_r($results);
foreach($results as $arrays){
foreach($arrays as $name){
return $name;
}
}
}
the problem is that I am constantly writing the line:
$db = new MysqliDb('localhost', 'root', 'root', 'my_db');
Is there a way I can declare the variable globally, have something more like this:
$db = new MysqliDb('localhost', 'root', 'root', 'my_db');
function add_post($userid,$body,$cat_id,$user_link){ //This function inserts new posts into the db
$now = date("Y-m-d H:i:s");
$insertData = array(
'user_id' => $userid,
'body' => $body,
'stamp' => $now,
'cat_id' => $cat_id,
'link' => $user_link
);
global $db->insert('posts', $insertData);
}
There are multiple ways to handle this but the best implementation can vary depending on the structure and needs of your action application.
You mentioned a global variable which would work, but is typically considered poor structure:
someFunction(){
global $db;
$db->insert('posts', $insertData);
}
Another method, which is slightly cleaner but still not as well organized is to pass the $db connection to the functions:
function myFunction( $db, ... ){
$db->query( // etc );
}
myFunction( $db );
A better version of this would be to organize your related functions in a class, and then inject the database:
class Posts {
public function listPosts( $db, ... ){
$db->query( // etc );
}
public function getPost( $db, ... ){
$db->query( // etc );
}
}
$posts = new Posts();
$posts->listPosts();
However, you can also decide to make these static methods, you could pass $db to the class constructor and store it, there are many choices.
You could also make a central wrapper class of your own that returns the connection. There are a million implementations but it's hard to specifically recommend one without knowing more about your application structure, how your classes share resources, how the application bootstraps everything - if it does. Etc
Try This:
db.php
class DB
{
public $conn;
private static $instance;
private function __construct()
{
$server = 'localhost';
$user = 'root';
$pass = 'root';
$database = 'my_db';
$this->conn = mysqli_connect($server,$user,$pass,$database);
}
public function query($sql)
{
$result = mysqli_query($this->conn,$sql);
return $result;
}
public static function getInstance()
{
if (!isset(self::$instance))
{
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
}
Now in any page you can do:
require("db.php");
$dbh = DB::getInstance();
$sql = "your sql query ..";
$dbh->query($sql);

Mysqli query error outside class

I made a db connection class like this :
class db_connector{
const host = "localhost";
const user = "root";
const password = "";
const dbname = "test";
public $db;
public function __construct()
{
$database = $this::dbname;
$db = new mysqli($this::host, $this::user, $this::password, $this::dbname);
if($db->connect_errno)
{
die (mysql_connect_error());
}
return $db;
}
}
When i create an object for the class it works fine enough, though then i want to make a query within the class i get the following error:
Fatal error: Call to undefined method db_connector::query()
The object is as follows (outside the class):
$con = new db_connector;
$con->query("SELECT * FROM test");
The connection gets established, just the query gives the error. I thought the object would inherit the mysqli methods since I returned it. Can anybody help me fix this one? Im fairly new in OOP so maybe my logic is not the best.
How about a little magic:
class db_connector{
protected $connectionData = array(
'host' => 'localhost',
'user' => 'root',
'password' => '',
'dbname' => 'test',
);
protected $db;
public function __construct($connectionData=array())
{
$cd = array_merge($this->connectionData, $connectionData);
$this->db = new mysqli($cd['host'], $cd['user'], $cd['password'], $cd['dbname']);
if($this->db->connect_errno)
{
die (mysql_connect_error());
}
}
public function foo()
{
return 'I am foo, i exist so i will be called even if mysqli::foo would exist, because i am defined in this class!';
}
public function __get($property)
{
if(property_exists($this->db, $property)){
return $this->db->$property;
}
}
public function __call($name, $args)
{
if(method_exists($this->db, $name))
return call_user_func_array(array($this->db, $name), $args);
}
}
And call it like:
$db = new db_connector();
$result = $db->query('SELECT foo FROM bar LIMIT 1');
// this should also work:
echo $result->num_rows;
The class constructor won't return the mysqli object as you expect.
$con = new db_connector;
//$con is a db_connector object not a mysqli object
$con->query("SELECT * FROM test");
Try:
$con = new db_connector;
$con->db->query("SELECT * FROM test");
instead. $con->db is a public field which holds the mysqli object.
Edit
Also change:
$db = new mysqli($this::host, $this::user, $this::password, $this::dbname);
if($db->connect_errno)
{
die (mysql_connect_error());
}
return $db;
To:
$this->db = new mysqli($this::host, $this::user, $this::password, $this::dbname);
if($this->db->connect_errno)
{
die (mysql_connect_error());
}

Categories