I was reading somewhere that using global variables is generally a bad idea but I am not sure what the alternative is...
I have this code now and I need to use global $config, $db in every single function. = copy & paste
class Layout {
public static function render($file, $vars) {
global $config, $mysql_db;
mysqli_query($mysql_db, "SELECT * FROM users");
}
}
Is there a better way to do this or do I need to use global keyword or define globals? Because I will need things like mysql connection variables in every function...
Generally speaking, global variables are not good. There are some methods to avoid global variables.
Use a base class
class Base
{
protected $db, $config;
}
class Layout extends Base
{
public void foo()
{
$this->db->query(...);
}
}
Use namespace
namespace MyProject
{
function DB()
{
....
}
}
class Layout
{
public void foo()
{
\MyProject\DB()->query(...);
}
}
Use some frameworks, like Symfony, Laravel, etc (also you can consider some ORM-only frameworks)
The famous frameworks do good job.
Symphony: https://symfony.com/doc/current/doctrine.html
Laravel: https://laravel.com/docs/5.6/database
ORM concept: What is an Object-Relational Mapping Framework?
Static variables in a class is one way to avoid them. Think of static variables in PHP as variables defined on the class rather the instance of the class. The singleton pattern then can grab the variable, or just reference the variable directly on the class. Alternatively, write a __construct method to accept in your incoming variables. Another approach is traits in PHP to help reduce on your copy pasting. Not saying traits are good practice, but they help avoid repeating yourself. Finally, there's almost always a way to abstract over the problem. Having your database connection in a method called render already violates the concept of separation of concerns, and the single responsibility principle. Dependency injection is probably my favorite way to solve the global issue. Find a framework or library that supports it. Lots of good choices out there. Either a framework like Laravel or some composer package that gets you the functionality you need will do.
This is basic example how you can use it
create Database class with file name Database.php
<?php
class Database{
private $con;
function __construct() {
$con = mysqli_connect("localhost","my_user","my_password","my_db");
}
function execute($sql){
// Perform queries, but you should use prepared statemnet of mysqli for
// sql injection
$execute = mysqli_query($con,$sql);
return $execute;
}
}
?>
And let say Render class with name Render.php
<?php
require_once('your_path/Database.php'); // write correct path of file
class Render{
private $db;
function __construct() {
$db = new Database();
}
function test(){
$result = $db->execute('SELECT * FROM users');
}
}
?>
A common pattern is to pass any required classes into the constructor of a class, so this would look more like...
class Layout {
private $config;
private $mysql_db;
public function __construct ( $config, $mysql_db ) {
$this->config = $config;
$this->mysql_db = $mysql_db;
}
public function render($file, $vars) {
$this->mysql_db->query( "SELECT * FROM users");
}
}
This is based around dependency injection (DI) which is common amongst frameworks and allows much more flexibility and control. First link from a search gives - http://php-di.org/doc/understanding-di.html.
Also note that I've changed the call to mysqli_query() to the object oriented interface query(), this requires you create the connection with something like new mysqli("localhost", "my_user", "my_password", "world"), but also makes the interface more consistent (you can change this back if you want)
This would then be created using
$layout = new Layout( $config, $mysql_db);
$layout->render($file, $vars);
This layout is core to a lot of frameworks and is also key when you want to undertake comprehensive testing as you can control the information being passed in and mock classes where needed.
A lot of posters have given beating around the bush answers ... sorry guys ... it's true.
The common way to take care of it is with Dependency Injection. Taking your class
class Layout {
public static function render($file, $vars) {
global $config, $mysql_db;
mysqli_query($mysql_db, "SELECT * FROM users");
}
}
You have a dependency on $config, $mysql_db; Your class depends on them. Typically you would Inject these into the constructor like this.
protected $Mysqli;
protected $config;
public function __construct(array $config, Mysqli $Mysqli){
$this->config = $config;
$this->Mysqli = $mysqli;
}
The issue you have is that the method itself is static, so that bypasses the guarantee that the constructor was called. You can just call the method directly. If possible I would change this to not be static.
But if you insist on keeping it static, then there is a few common ways to solve this, and it depends what the rest of the class looks like. For these I will ignore $config (for the most part) it's not used and it's not clear how it's used or what it's used for (I'm assuming it's for the database). I will also use the Object interface to Mysqli instead of the procedural one.
The most obvious way it to stick them in the method call
public static function render($file, $vars, Mysqli $Mysqli) {
$Mysqli->query("SELECT * FROM users");
}
You can check when the method is called and connect
protected static $Mysqli;
public static function connect(){
//this has the obvious problem of getting the connection info.
$config = require 'config.php';
if(!is_array($config)) throw new Exception('Bad config..'); //etc.
self::$Mysqli = new mysqli(
$config['dbhost'],
$config['dbuser'],
$config['dbpass'],
$config['dbname']
);
}
public static function render($file, $vars) {
if(!$Mysqli) self::connect();
self::$Mysqli->query("SELECT * FROM users");
}
//config.php would look like this
<?php
return [
'dbname' => 'database',
'dbuser' => 'username',
'dbpass' => 'password',
'dbhost' => 'host'
];
This works but it may not be Ideal because now your class is responsible for an external file config.php which if it doesn't exist will cause issues.
You can use a singleton pattern if this class is all static methods. This saves a reference to the class instance (it's self) in a static property. Then when you call getInstance it always returns the same instance, that is way it is called a singleton
class Layout {
//saves a reference to self
private static $instance;
protected $Mysqli;
final private function __construct(Mysqli $Mysqli){
if(!$Mysqli) throw new Exception('Instance of Mysqli required');
$this->Mysqli = $Mysqli;
}
final private function __clone(){}
final private function __wakeup(){}
public static function getInstance(Mysqli $Mysqli = null)
{
if (!self::$instance)
self::$instance = new self($Mysqli);
return self::$instance;
}
public function render($file, $vars) {
self::$Mysqli->query("SELECT * FROM users");
}
}
$Layout = Layout::getInstance();
$Layout->render($file, $vars);
The problem with this is the first call the Mysqli class (or config or whatever) is required, but on subsequent calls it's not. You may or may not know ahead of time that its the first call. But again you could load the config from a file in this example too.
You'll also notice a few methods are Final private this is to prevent overloading and calling them from outside the class.
I also have a trait for Singleton and Multiton (singleton container, multiple Singletons) that I put up on GitHub and Composer, you can find that here
https://github.com/ArtisticPhoenix/Pattern/
Each has it's advantages and disadvantages.
P.S. I just typed these all out on this page, so I didn't test any of them but the theory is sound....
Problems with global variables
you will have trouble naming new global variables, accidentally overriding useful data in your formerly defined global variables
your code might keep unreasonably variables that you no longer need, with all the consequences
There is always an exception from the rule
However, it is better to avoid dogmatic extremism. Sometimes you will need global variables for some reason, but you will need to make sure that you have a very good reason to use global variables.
Alternative
The alternative for using global variables everywhere is to use private or protected class members, initializing the main values via a constructor, like:
class Layout {
private $config;
private $mysql_db;
public function render($file, $vars) {
mysqli_query($mysql_db, "SELECT * FROM users");
}
public function __construct($config, $mysql_db) {
$this->config = $config;
$this->mysql_db = $mysql_db;
}
}
And then you can instantiate Layout via the new keyword and call render of its instance.
Further notes
Also, you can use namespaces so you might have several classes with the same name and I would like to mention local variables as well, inside functions.
Related
A couple of the options are:
$connection = {my db connection/object};
function PassedIn($connection) { ... }
function PassedByReference(&$connection) { ... }
function UsingGlobal() {
global $connection;
...
}
So, passed in, passed by reference, or using global. I'm thinking in functions that are only used within 1 project that will only have 1 database connection. If there are multiple connections, the definitely passed in or passed by reference.
I'm thining passed by reference is not needed when you are in PHP5 using an object, so then passed in or using global are the 2 possibilities.
The reason I'm asking is because I'm getting tired of always putting in $connection into my function parameters.
I use a Singleton ResourceManager class to handle stuff like DB connections and config settings through a whole app:
class ResourceManager {
private static $DB;
private static $Config;
public static function get($resource, $options = false) {
if (property_exists('ResourceManager', $resource)) {
if (empty(self::$$resource)) {
self::_init_resource($resource, $options);
}
if (!empty(self::$$resource)) {
return self::$$resource;
}
}
return null;
}
private static function _init_resource($resource, $options = null) {
if ($resource == 'DB') {
$dsn = 'mysql:host=localhost';
$username = 'my_username';
$password = 'p4ssw0rd';
try {
self::$DB = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
} elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
self::$$resource = new $resource($options);
}
}
}
And then in functions / objects / where ever:
function doDBThingy() {
$db = ResourceManager::get('DB');
if ($db) {
$stmt = $db->prepare('SELECT * FROM `table`');
etc...
}
}
I use it to store messages, error messages and warnings, as well as global variables. There's an interesting question here on when to actually use this type of class.
Try designing your code in an object-oriented fashion. Methods that use the database should be grouped in a class, and the class instance should contain the database connection as a class variable. That way the database connection is available to the functions that need it, but it's not global.
class MyClass {
protected $_db;
public function __construct($db)
{
$this->_db = $db;
}
public function doSomething()
{
$this->_db->query(...);
}
}
I see that a lot of people have suggested some kind of static variable.
Essentially, there is very little difference between a global variable and a static variable. Except for the syntax, they have exactly the same characteristics. As such, you are gaining nothing at all, by replacing a global variable with a static variable. In most examples, there is a level of decoupling in that the static variable isn't referred directly, but rather through a static method (Eg. a singleton or static registry). While slightly better, this still has the problems of a global scope. If you ever need to use more than one database connection in your application, you're screwed. If you ever want to know which parts of your code has side-effects, you need to manually inspect the implementation. That's not stuff that will make or break your application, but it will make it harder to maintain.
I propose that you chose between one of:
Pass the instance as arguments to the functions that needs it. This is by far the simplest, and it has all the benefits of narrow scope, but it can get rather unwieldy. It is also a source for introducing dependencies, since some parts of your code may end up becoming a middleman. If that happens, go on to ..
Put the instance in the scope of the object, which has the method that needs it. Eg. if the method Foo->doStuff() needs a database connection, pass it in Foo's constructor and set it as a protected instance variable on Foo. You can still end up with some of the problems of passing in the method, but it's generally less of a problem with unwieldy constructors, than with methods. If your application gets big enough, you can use a dependency injection container to automate this.
My advice is to avoid global in the bulk of the code - it's dangerous, hard to track and will bite you.
The way that I'd do this is to have a function called getDB() which can either be at class level by way of a constructor injection or static within a common class.
So the code becomes
class SomeClass {
protected $dbc;
public function __construct($db) {
$this->dbc = $db;
}
public function getDB() {
return $this->dbc;
}
function read_something() {
$db = getDB();
$db->query();
}
}
or using a common shared class.
function read_something() {
$db = System::getDB();
$db->query();
}
No matter how much elegant system design you do, there are always a few items that are necessarily global in scope (such as DB, Session, Config), and I prefer to keep these as static methods in my System class.
Having each class require a connection via the constructor is the best way of doing this, by best I mean most reliable and isolated.
However be aware that using a common shared class to do this can impact on the ability to isolate fully the objects using it and also the ability to perform unit tests on these objects.
None of the above.
All the mysql functions take the database connection argument optionally. If you leave that argument out, the last connection by mysql_connect() is assumed.
function usingFunc() {
$connection = getConnection();
...
}
function getConnection() {
static $connectionObject = null;
if ($connectionObject == null) {
$connectionObject = connectFoo("whatever","connection","method","you","choose");
}
return $connectionObject;
}
This way, the static $connectionObject is preserved between getConnection calls.
So I've come across a "problem" with PHP classes.
I have a few classes that require functions from one another, so at the moment I am doing the following:
$db = new blueConnect;
$core = new blueCore($db);
$users = new blueUsers($db, $core);
then within the file:
public function __construct(blueConnect $db, blueCore $core) {
$this->db = $db;
$this->core = $core;
}
However instead of doing this for each file that required additional functions, would it be better to write
global $db, $core
within each of the functions that require it?
The Name of the Pattern that you are talking about is called "Dependency Injection" or DI in short.
Depending on your Project using global might solve the problem in a short term but if you plan to create a big project that you later on test and share with multiple people you would like to avoid using global at all. - You can not test or debug that stuff well.
A (bad) solution is to make your database and core Class use the Singleton Pattern to avoid global but have the same effect. (not testable, not configurable)
public function __construct() {
$this->db = blueConnect::getInstance();
$this->core = blueCore::getInstance();
}
The solution for this is usually to create a Factory function that creates all of your Services that need the Database and the Core.
public function createService($name) {
$serviceClass = 'blue'.ucfirst($name).'Service';
return new $serviceClass($this->getDatabase(), $this->getCore());
}
And this Function is usually part of a Registry or better an DI Container like for example PIMPLE
Example with Only one Instance of each Service:
public function createService($name) {
$serviceClass = 'blue'.ucfirst($name).'Service';
static $services = array();
if(!isset($services[$name])) {
$services[$name] = new $serviceClass($this->getDatabase(), $this->getCore());
}
return $services[$name];
}
Be aware that you should NOT test with your Registry / DI Container since you have a "global" state inside of your container. (e.g. fetching the same service twice)
I would not use globals.
Reasons:
It's just not the OOP way.
Hard to debug.
The resulting code would not be testable. If you want your application to be covered by unit tests you should use Dependcy Injection as you currently do. I'll try to briefly explain why. Unit testing as its name implies is just that: testing a single unit of your application, i.e. your classes (their public methods).
Now let's suppose you use global variables that get set somewhere in your app. You won't be able to test your blueUsers class as a standalone unit because you will need the $db and $core objects to be instantiated. Therefore you won't be able to just include the blueUsers.php file and test the class because you will need other parts of your application (those which define the global variables $db and $core).
If on the other hand you used Dependcy Injection you wouldn't face such an issue. The only things you'll need to do in order to test the blueUsers class would be to include the class, create mocks of the dependencies $db and $core, and pass them to the blueUsers constructor.
Here's a nice source for more detailed explanation on how to write testable and maintainable code.
And here you could find more information about mocking and whether and what you can benefit from using it.
I'd use a singletone to contain the global objects. It's easily accessible by other objects and it provides a safe access to those variables:
final class GlobalObjects
{
public static function Instance()
{
static $inst = null;
if ($inst === null) {
$inst = new GlobalObjects();
}
return $inst;
}
private function __construct() {
$db = new blueConnect;
$core = new blueCore($db);
}
public function getDb() { return $this->db; }
public function getCore() { return $this->core; }
}
// ...
public function __construct() {
$this->db = GlobalObjects::Instance()->getDb();
$this->core = GlobalObjects::Instance()->getCore();
}
Another approach that comes into my mind, a simpler and dirtier one, is: as those variables are global objects it might be worth to define them as constants to avoid mistakes:
define( "db", new blueConnect );
define( "core", new blueCore($db) );
$users = new blueUsers($db, $core);
And then
public function __construct() {
global $db, $core;
$this->db = $db;
$this->core = $core;
}
If the parameters are dynamic and variable, you should pass them in constructor, so new blueUsers($db, $core, ...) is better. But if these are static parameter, and you don't need to pass them when initialization of the class, you should define as global.
I'm moving onto teaching myself OOP in PHP.
I'm creating a couple of little web apps and have followed a lot of tutorials that either create the database (using PDO) via a Singleton, or via passing the global around. I've read that these are pretty much the same thing and are both to be avoided like the plague.
So I've watched the Google Tech Talks on clean code, and read almost every SO article on dependency injection and the like. I have a couple of questions.
The clean code videos suggest you shouldn't do 'work' in your constructors. Is this 'work' in reference to business logic. Ie. If my class's job is to create another object, is that an OK kind of 'work'?
For example, in trying to conform to single repsonibility classes I created three.
Class DB - which actually connects to the database.
Class DBFactory - which creates the DB object which connects to the database.
Class DBInstance - which returns a single instance of the DBFactory created PDO object.
Please note that I'm trying to create a single instance, without creating a Singleton pattern.
So I try and pass my dependencies for each class up the chain. I find myself in a position where I have to create all of the objects (from DB down) so I can inject the dependencies. For some reason I thought it would work the other way, I'd create the first object, which would create the second for me etc. I'm clearly missing something?
Hopefully this helps others as well - there seems to be a myriad of questions relating to this stuff and databases but very little good examples.
(I should mention this does work, I do get a list of hotel names out of the database!)
TestCode.php
include './classes/DB.php';
include './classes/DBFactory.php';
include './classes/DBInstance.php';
include './classes/Location.php';
$db = new DB;
$dbfactory = new DBFactory($db);
$dbinstance = new DBInstance($dbfactory);
$dbh = $dbinstance->getDbInstance();
//Example business logic
$location_names = Location::getLocationNames($dbh);
print_r($location_names);
Class DB.php:
class DB {
private $_dbhost = 'myhost';
private $_dbname = 'myname';
private $_dbuser = 'myuser';
private $_dbpass = 'mypass';
private $_error;
public function connect() {
try {
return new PDO("mysql:host=$this->_dbhost;dbname=$this->_dbname",
$this->_dbuser, $this->_dbpass);
}
catch (PDOException $e) {
$this->_error = 'Error! ' . $e->getMessage() . '<br />';
die();
}
}
public function getError() {
if (isset($this->_error)) {
return $this->_error;
}
}
}
Class DBFactory.php
class DBFactory {
private $_dbh;
public function __construct(DB $db) {
$this->_dbh = $db;
}
public function Create() {
return $this->_dbh->Connect();
}
}
Class DBInstance.php
class DBInstance {
private static $_dbinstance;
public function __construct(DBFactory $dbfactory) {
if (!isset(self::$_dbinstance)) {
self::$_dbinstance = $dbfactory->Create();
}
}
public function getDbInstance() {
return self::$_dbinstance;
}
}
Your code seems to do what you want it to.. but maybe we can use less object instantiation using inheritance and maybe we can avoid static properties in instanciated classes.
Also in regard to using a pattern of dependency injection that is able to handle multiple connections, but support using a single instance of it. exemple first, classes after
$params = array
('host'=>'localhost',
'db'=>'ice',
'user'=>'kopitar',
'pass'=>'topnet',
'charset'=>'utf8'); // passing the charset explicitely is great
$handle = new handle($params);
$db = $handle->getInstance();
we can either pass the $db to our functions
$location_names = Location::getLocationNames($db);
or the whole $handle. as long as $handle is not reconstructed, it will always return the same database connection.
$location_names = Location::getLocationNames($handle);
if I want to reconstruct I need the whole $handle
$handle->__construct(/* params but with another database infos */);
$db2 = $handle->getInstance();
As for the classes, I think we want the params to arrive from the instanciated class, so we can change them later.
class db {
function __construct($params) {
foreach ($params as $param => $value) {
$this->{$param} = $value; // assigns the connections infos
}
}
protected function connect() {
$dsn = 'mysql:host='.$this->host.';dbname='.$this->db.';charset='.$this->charset;
return new PDO($dsn,$this->user,$this->pass);
}
}
the factory creates a connection from params and passes it to something else, good factory
class factory extends db {
protected function create() {
return $this->connect();
}
}
now we want to have our object to keep it's connection as long as we do not rebuild it. so we give it to instance
class instance extends factory {
function instantiate() {
$this->instance = $this->create();
}
}
and last but not least, our handle which returns the instance. it could be in instance class.....................
but I feel like having four and find no real reason not to.
class handle extends instance {
function __construct($params) {
db::__construct($params);
$this->instantiate(); // when we construct a handle, we assign an instance to the instance property
}
function getInstance() {
return $this->instance;
}
}
KISS
Don't make things more complex than they are, of course this is just my opinion, but as I see it you are building a complex solution for a problem that someone else says might exist is some cases.
Php is not multi threaded so there goes one of the biggest arguments overboard. (in very rare-occasions it might be)
I'm using singletons for my database connections for about 15 years now and never ever had a problem with them, I do play around with different connections having one singleton handle several connection instances, but whatever... it works great and everyone that looks at the code.. understands it directly.
I'm not using globals because they can be overwritten and are kind of hard to predict (when it holds the correct object, and when/why they don't)
Use OOP to make your code cleaner, easier to work with and more flexible.
Don't use it to fix problems that aren't there and make your code more complex because others tell you to.
An very simple example of a db-connection singleton class handling several different connections.
class singleton{
private static $_instances=array();
public static function getInstance($connectionName){
if(!isset(self::$_instance[$connectionName]){
self::$_instance[$connectionName]=self::_getConnection($connectionName);
}
return self::$_instance[$connectionName];
}
}
just my 2 cents
Why do you have a factory if you have a singleton? This is needless.
This is a never-ending debate, but I'm advocate of do not use singletons for database connections.
As far as in most applications, you have only one data channel, you can consider your database connection unique, but this might not be always true.
In deed, the effort made to create a singleton database connection is even bigger than just create a regular one.
Also, your class DB is not configurable, therefore, you need to change it when your connection parameters change. And I think DB is a very bad name for this.
I'd rather call this Storage and do something like:
inteface Storage {
public function insert($container, array $data);
public function update($container, array $data, $where);
public function delete($container, $where);
public function getAll($container);
public function getOne($identifier);
}
final class PdoStorage implements Storage {
private $dbh;
private $dsn;
private $user;
private $pswd;
public function __construct($dsn, $user, $pswd) {
$this->dsn = $dsn;
$this->user = $user;
$this->pswd = $pswd;
}
// Lazy Initialization
private function connect() {
if ($this->dbh === null)
$this->dbh = new PDO($this->dsn, $this->user, $this->pswd);
}
public function insert($container, array $data) {
$this->connect();
// ... omitted for brevity
}
}
Now, when you need a database storage, you do:
$someObj = new SomeClass(new PdoStorage(...));
Now you might be wondering if you will need to create an PdoStorage for each single object that depends on it.
The answer is: no!
Now you can use a factory to simplify your life.
class SomeFactory {
private $defaultStorage;
public function __construct(Storage $storage) {
$this->defaultStorage = $storage;
}
public function create($type) {
// Somehow fetches the correct class to instantiate and put it into $class variable , for example... and then
return new $class($this->defaultStorage); // Or you'd better do this with reflection
}
}
$factory = new SomeFactory(new PdoStorage(...));
$factory->create('SomeClass');
This way, you can have just one database connector or more if you need.
I have a database class, which an instance is declared in the main index.php as
$db = new Database();
Is there a way for the $db variable to be globally recognized in all other classes without having to declare
global $db;
in the constructor of each class?
No. You have to declare Global $db in the constructor of every class.
or you can use the Global array: $_GLOBALS['vars'];
The only way to get around this is to use a static class to wrap it, called the Singleton Method (See Here for an explanation). But this is very bad practice.
class myClass
{
static $class = false;
static function get_connection()
{
if(self::$class == false)
{
self::$class = new myClass;
}
else
{
return self::$class;
}
}
// Then create regular class functions.
}
The singleton method was created to make sure there was only one instance of any class. But, because people use it as a way to shortcut globalling, it becomes known as lazy/bad programming.
StackOverflow Knowledge
How to Avoid Using PHP Global Objects
Share Variables Between Functions in PHP Without Using Globals
Making a Global Variable Accessible For Every Function inside a Class
Global or Singleton for Database Connection
I do it a little different. I usually have a global application object (App). Within that object I do some basic initialization like creating my db objects, caching objects, etc.
I also have a global function that returns the App object....thus (application object definition not shown):
define('APPLICATION_ID', 'myApplication');
${APPLICATION_ID} = new App;
function app() {
return $GLOBALS[APPLICATION_ID];
}
So then I can use something like the following anywhere in any code to reference objects within the global object:
app()->db->read($statement);
app()->cache->get($cacheKey);
app()->debug->set($message);
app()->user->getInfo();
It's not perfect but I find it to make things easier in many circumstances.
you could use
$GLOBALS['db']->doStuff();
or alternatively using some kind of singleton access method
Database::getInstance()->doStuff();
Why not create a class that contains the global $db; in it's constructor, then extend all other classes from this?
You could use a Registry class to store and retrieve your Database instance.
class Registry
{
protected static $_data = array();
public static function set($key, $value)
{
self::$_data[$key] = $value;
}
public static function get($key, $default = null)
{
if (array_key_exists($key, self::$_data)) {
return self::$_data[$key];
}
return $default;
}
}
Registry::set('db', new Database());
$db = Registry::get('db');
A couple of the options are:
$connection = {my db connection/object};
function PassedIn($connection) { ... }
function PassedByReference(&$connection) { ... }
function UsingGlobal() {
global $connection;
...
}
So, passed in, passed by reference, or using global. I'm thinking in functions that are only used within 1 project that will only have 1 database connection. If there are multiple connections, the definitely passed in or passed by reference.
I'm thining passed by reference is not needed when you are in PHP5 using an object, so then passed in or using global are the 2 possibilities.
The reason I'm asking is because I'm getting tired of always putting in $connection into my function parameters.
I use a Singleton ResourceManager class to handle stuff like DB connections and config settings through a whole app:
class ResourceManager {
private static $DB;
private static $Config;
public static function get($resource, $options = false) {
if (property_exists('ResourceManager', $resource)) {
if (empty(self::$$resource)) {
self::_init_resource($resource, $options);
}
if (!empty(self::$$resource)) {
return self::$$resource;
}
}
return null;
}
private static function _init_resource($resource, $options = null) {
if ($resource == 'DB') {
$dsn = 'mysql:host=localhost';
$username = 'my_username';
$password = 'p4ssw0rd';
try {
self::$DB = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
} elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
self::$$resource = new $resource($options);
}
}
}
And then in functions / objects / where ever:
function doDBThingy() {
$db = ResourceManager::get('DB');
if ($db) {
$stmt = $db->prepare('SELECT * FROM `table`');
etc...
}
}
I use it to store messages, error messages and warnings, as well as global variables. There's an interesting question here on when to actually use this type of class.
Try designing your code in an object-oriented fashion. Methods that use the database should be grouped in a class, and the class instance should contain the database connection as a class variable. That way the database connection is available to the functions that need it, but it's not global.
class MyClass {
protected $_db;
public function __construct($db)
{
$this->_db = $db;
}
public function doSomething()
{
$this->_db->query(...);
}
}
I see that a lot of people have suggested some kind of static variable.
Essentially, there is very little difference between a global variable and a static variable. Except for the syntax, they have exactly the same characteristics. As such, you are gaining nothing at all, by replacing a global variable with a static variable. In most examples, there is a level of decoupling in that the static variable isn't referred directly, but rather through a static method (Eg. a singleton or static registry). While slightly better, this still has the problems of a global scope. If you ever need to use more than one database connection in your application, you're screwed. If you ever want to know which parts of your code has side-effects, you need to manually inspect the implementation. That's not stuff that will make or break your application, but it will make it harder to maintain.
I propose that you chose between one of:
Pass the instance as arguments to the functions that needs it. This is by far the simplest, and it has all the benefits of narrow scope, but it can get rather unwieldy. It is also a source for introducing dependencies, since some parts of your code may end up becoming a middleman. If that happens, go on to ..
Put the instance in the scope of the object, which has the method that needs it. Eg. if the method Foo->doStuff() needs a database connection, pass it in Foo's constructor and set it as a protected instance variable on Foo. You can still end up with some of the problems of passing in the method, but it's generally less of a problem with unwieldy constructors, than with methods. If your application gets big enough, you can use a dependency injection container to automate this.
My advice is to avoid global in the bulk of the code - it's dangerous, hard to track and will bite you.
The way that I'd do this is to have a function called getDB() which can either be at class level by way of a constructor injection or static within a common class.
So the code becomes
class SomeClass {
protected $dbc;
public function __construct($db) {
$this->dbc = $db;
}
public function getDB() {
return $this->dbc;
}
function read_something() {
$db = getDB();
$db->query();
}
}
or using a common shared class.
function read_something() {
$db = System::getDB();
$db->query();
}
No matter how much elegant system design you do, there are always a few items that are necessarily global in scope (such as DB, Session, Config), and I prefer to keep these as static methods in my System class.
Having each class require a connection via the constructor is the best way of doing this, by best I mean most reliable and isolated.
However be aware that using a common shared class to do this can impact on the ability to isolate fully the objects using it and also the ability to perform unit tests on these objects.
None of the above.
All the mysql functions take the database connection argument optionally. If you leave that argument out, the last connection by mysql_connect() is assumed.
function usingFunc() {
$connection = getConnection();
...
}
function getConnection() {
static $connectionObject = null;
if ($connectionObject == null) {
$connectionObject = connectFoo("whatever","connection","method","you","choose");
}
return $connectionObject;
}
This way, the static $connectionObject is preserved between getConnection calls.