I have a small question regarding the use of Global.
I downloaded a Query class, and changed/added several things including switched to mysqli, finally there is some different roles that need to link mysql to another page with variable settings.
Finally the functions of the class, need to call the variable $ mysqli, so I have to declare at the start of the function global $mysqli;
There is a way to declare this variable for all functions at once page?
You really shouldn't use global for this. You should pass the $mysqli object in as a parameter to the constructor ad refer to $this->mysqli from within your methods.
For example:
class myDb {
private $mysqli;
function __construct($mysqli) {
$this->mysqli = $mysqli;
}
function queryDb($query) {
return $this->mysqli->query($query);
}
}
Related
I have a Database class for connecting to DB.
<?php
require_once('config.php');
class Database {
function __construct(){
$this->connect();
}
public function connect(){
$this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE);
}
}
?>
And a main class where I need to use the DB connection:
include 'includes/database.php';
class Main{
var $mysqli;
public function __construct(){
$this->mysqli = new Database();
}
But this is not working, since I get an error for queries that are still in the main classes, I intend to move them to the DB class later. But now I am getting an error:
Fatal error: Uncaught Error: Call to undefined method
Database::query() in /home/vagrant/Projects/MyProject/index.php
on line 262
Queries are done in the Main class:
$result = $this->mysqli->query( "SELECT shops.*, shops.id AS shop,SUM(price)...
You are trying to call a query() method on the Database class. While that class contains a mysqli object in its $connection property, it does not expose the query() method of that mysqli object.
Given your current code, you could drill further into the object structure to call query() directly on the mysqli, but this is messy.
// Call the query() method directly on the connection
$result = $this->mysqli->connection->query( "SELECT shops.*, shops.id AS shop,SUM(price)...
I don't like this approach because it requires that your classes know more about the inner workings of the Database class than they probably should. It couples them too tightly.
As an alternative, you could create a query() method in the Database class that wraps the necessary functionality of the mysqli object within it.
class Database {
function __construct(){
$this->connect();
}
public function connect(){
$this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE);
}
// Expose a query() method that calles the inner mysqli's query
public function query($sql) {
return $this->connection->query($sql);
}
}
This would allow you to pack in more functionality, such as querying and fetching all result rows in one method call:
class Database {
//....
// A more featured query() that returns the
// rows as an array
public function query($sql) {
$result = $this->connection->query($sql);
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
// Return an array of all the rows fetched from the query
return $rows;
}
}
If you do it this way, you should be able to call $this->mysqli->query("...") as you originally attempted and either get back the result resource with the simple version, after which you must fetch in the code yourself, or get back an array of associative result rows in the more featured version.
Creating these kinds of database wrapper classes can get unwieldy rather quickly though. Think carefully about what aspects of the mysqli object you want to expose to the other classes in your application. It's not a good idea to go down a path of wrapping every mysqli method in your Database class. At that point, the utility of the Database class is greatly reduced and you may as well just be passing in a mysqli object directly. If you are not actively adding functionality to mysqli, it makes less sense to create another class that wraps it.
A note about the var $mysqli;... This is an old deprecated class property syntax. The var keyword is a vestige from PHP4 and its use is discouraged nowadays. In fact, it has been removed from recent PHP versions. Instead, you should declare it via the PHP5+ syntax:
// Declare as a public property
public $mysqli;
// Or better, as a private (or protected) property so it cannot
// be accessed outside the Main class' own methods
private $mysqli;
In your question title, you mentioned injection. Your class doesn't do that right now, but it would be a good idea to instantiate a Database ahead of time and inject one into the class constructors that need it.
class Main{
public $mysqli;
// Pass a database as a constructor param
public function __construct($database){
$this->mysqli = $database;
}
Then instantiate it as:
$db = new Database();
// Pass the $db to the other classes
$main = new Main($db);
Importantly, this will prevent you from opening up a separate database connection for each object you instantiate of Main and any other class you construct in the same way. Doing that can quickly use up the server's available MySQL connections.
I had this error:
Notice: Undefined variable: mysqli in /path/to/component.php on line 24
This was inside this section of code:
class Component {
public function foo() {
// something using $mysqli;
}
}
To fix it, I have to add global $mysqli into my foo method - I understand that, but this isn't very practical for me, as I'd prefer to simply make $mysqli accessible within all classes by default.
Is this possible?
The short answer is: no. There isn't a way to change the way scope is handled in PHP.
Since that's probably not very helpful to you, I'll try to explain a better approach.
The global keyword is one of PHP's idiosyncrasies. Some people think it's dumb, but there's a certain logic to it. Lots of patterns in programming are about keeping dependencies explicit. Stuff that happens inside your class shouldn't depend on the state of the world outside. In your case (or whenever you import a global variable using global, you're coupling your class to the environment it lives in. This is bad for various reasons.
If your class requires a database connection, you should be injecting the dependency explicitly, not implicitly pulling it from global scope.
If the dependency is required for the class to function, the obvious place to inject it is in the constructor.
For example:
<?php
class MyComponent
{
/**
* #param mysqli $mysqli
*/
public function __construct($mysqli)
{
$this->mysqli = $mysqli;
}
public function getBars()
{
$bars = $this->mysqli->query('...');
return $bars;
}
}
// now back in the global scope
$mysqli = mysqli_connect('localhost', 'joe', 'secret', 'foodb');
$component = new MyComponent($mysqli);
$bars = $component->getBars();
For some project it is completely acceptable to have a single database and connection to it. Willing to access it from everywhere without using nasty global or injecting it all over the place make perfect sense.
One way I did is was simply to have my connection in a Static Object which is accessible from anywhere in my project. How I got this to work:
Use Composer to autoload my classes without having to worry about it. There are some details about how to do this here: Using Composer's Autoload
Create a class for the database connection.
class Database
{
public static $connection;
public static function connect($host, $user, $password, $database)
{
self:$connection = mysqli_connect($host, $user, $password, $database);
}
}
You can now access Database::$connection from anywhere as long as Composer includes your Database class. No need for globals...
Static classes can be quite useful for these type of usage. But some people don't like them because they are harder to test in some cases. There is no perfect solution, but do what make sense while trying to avoid bad patterns at all costs.
You may send it into constructor:
class Component {
protected $mysqli;
public function Component($mysqli = null) {
$this->mysqli = $mysqli;
}
public function foo() {
// something using $mysqli;
}
}
or set it by other methot of class after creating:
class Component {
protected $mysqli;
public function SetDBClass($mysqli)
{
$this->mysqli = $mysqli;
}
public function foo()
{
// something using $mysqli;
}
}
Use global keyword before declaration of your variable
Or put it into $GLOBALS array.
For more information about variable scope, take a look at this link: http://php.net/manual/en/language.variables.scope.php#language.variables.scope.global
I'm planning to use a PHP PDO wrapper class from here: http://www.imavex.com/php-pdo-wrapper-class/
I initialized the class with:
$db = new db("mysql:host=$sitedbHost;port=3306;dbname=$sitedbName", "$sitedbUser", "$sitedbPass");
The problem is, that I don't like the idea to make global $db on every function on my other classes like this:
class User
{
function getUserDomains($user_id)
{
global $db;
return $db->select("domains");
}
}
Any help will be highly appreciated.
If you class requires it in order to work, you can inject it in the constructor:
class User {
public function __construct(Database $db) {
$this->db = $db;
}
}
You can then access the database object from $this->db. (Note, I assumed $db is an instance of the Database class. Change it as appropriate).
Here is something for you:
Check new PDO Class Wrapper on GitHub
I don't like the idea to make global $db on every function on my other classes
Well, make it global in constructor only (or pass it as a parameter), and then use as a class variable,
return $this->db->select("domains");
Honestly, you can't avoid passing $db to the function somehow. There is no magic. Whatever fashionable way you choose, you'll end up with setting your $db variable this way or another, no matter how it's called, "dependence injection", "global" or "use the Force, Luke".
I'd vote for global as it's plain and simple.
By the way, this framework is inflexible and insecure. Better use safeMysql as it's way more secure and flexible
I have a file, standalone.php, that's meant to be run as its own script, directly from the browser. It defines functions, classes and includes other files. It works fine when directly invoked.
It has code in it like this:
$DB = new Database(DB_DATABASE, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, DB_SERVER, '', true);
function DB() { global $DB; return $DB; }
When run alone, $DB is defined in the global name space, and the function that returns the object grabs the global $DB object. Again, this works.
The problem is, i have another file, sometimesInvoker.php, that is called from the browser, and in some cases, needs to include standalone.php and output to the browser as if standalone.php had been invoked directly. It cannot use a redirect, and it cannot include standalone.php via URL.
The code in sometimesInvoker.php is:
LoadPage();
function LoadPage(){
include standalone.php;
}
So the hierarchy looks like:
Global name space / sometimesInvoker.php
LoadPage() function
standalone.php - thinks its global but it isn't
$DB - declared intending to be global but is actually a variable inside LoadPage() function?
function DB() - calls global DB and looks inside sometimesInvoker.php for a $DB var which isn't there, should be going up one level to LoadPage() function and grabbing that var.
So I get the problem, but how to solve it? I need a way for a function to get a variable that is one level above it, regardless of if the next level up is global or not. Any ideas?
In sometimesInvoker.php make the very first line require_once 'standalone.php';
I need a way for a function to get a variable that is one level above it, regardless of if the next level up is global or not.
I don't know if i understand you correctly but, there are a few ways of making variables available in sub functions;
Use "global" to use variables in another scope:
$db='whatever';
function XXYYY(){
global $db;
echo $db;
}
Or pass the variables into the function:
$db='whatever';
function XXYYY($db){
echo $db;
}
Or am i missing the point?
This is a workaround I'm using to solve the problem for now. Change the DB() function to:
function DB() {
static $DB = null;
if(is_null($DB))
$DB = new Database(DB_DATABASE, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, DB_SERVER, '', true);
return $DB;
}
Using a static variable in the DB function let's me instantiate the class once instead of relying on a global var. This solves the problem in this case, but I'd still be interested to know if you can access a var outside of a function if that var is in a parent function, not the global namespace?
inside of a function i have a $connection var what obviously stores my connection to mysql,
how can i call that var from inside other functions to save me having to paste the $connection var inside of every function that requires this var?
i have tried global to no avail.
many thanks
You could use the old global keyword.
function a() {
global $connection;
}
Or you could throw it in $GLOBALS (this will help you get it out of the function defined it in).
Neither of them are too pretty.
Or you could pass in the $connection as an argument.
The most common way of dealing with a database connection is to have its creation handled by a singleton pattern, or have a base class with OO that has a $this->db available, that all your other classes can inherit from.
Pass the connection as a parameter to the functions that need it. It keeps your code clean and re-usable.
Another solution would be to use a class and make the connection a class variable. You will just use $this->connection every time you need this, but this is not really a solution if you already have a lot of code written in a lot of files.
Declare the variable outside the function, then make it accessible inside each function you need it by using the global keyword.
$globalName = "Zoe";
function sayHello() {
$localName = "Harry";
echo "Hello, $localName!";
global $globalName;
echo "Hello, $globalName!";
}
sayHello();
stolen from http://www.elated.com/articles/php-variable-scope-all-you-need-to-know/