I am coding my first object factory, and I am wondering if there any any drawbacks to passing one object into another when creating the second object, and then saving the first object within the second for use later?
Example:
class main
{
public $connection = array();
// various other useful functions that should be loaded on every page here
// these other functions would be convenient to have avail for
// new objects in different classes
function dbconnect($db) {
if(!isset($this->connection[$db])) {
switch($db) {
case "users":
$connection = #mysql_connect(info,info,info);
$db_select = #mysql_select_db(info,$connection);
$this->connection[$db] = $connection;
break;
case "ads":
$connection = mysql_connect(info,info,info);
$db_select = mysql_select_db(info,$connection);
$this->connection[$db] = $connection;
break;
default:
die($db . " is not a recognized database.");
break;
}
}
return $this->connection[$db];
}
// note how i pass $this into the new object in this function
function create($class,$params=null) {
if(!class_exists($class) && !$this->load($class)) {
die($class . " is not a recognized class.");
}else{
return new $class($this,$params);
}
}
function load($file) {
$file = $_SERVER['DOCUMENT_ROOT'] . "/classes/" . $file . ".class.php";
if(file_exists($file)) {
return require_once($file);
}else{
return false;
}
}
}
class secondary {
private $connection;
private $mainObj;
private $params;
function __construct($mainObj,$params) {
$this->mainObj = $mainObj;
$this->params = $params;
$this->connection = $mainObj->dbconnect('users');
}
}
As you see here, any class created by the factory conveniently has the ability to connect to the MySQL db if the class requires it (and other common/useful functions) ... without having to use globals, or pass many things in.
Is this a stable way? I am new, and could use some good theory/schooling on why this is wrong - if it is.
Yes, it is a pretty stable way. But I would like to see type hinting in the methods taking outer instances as parameters, which would make your classes typed stronger.
Example;
class Alob {
public function aMethod(**Blob** $outerObject) {
...
}
}
class Blob {
...
}
This will throw a fatal error if Alob::aMethod() is called with another type than Blob.
I would also like to see more accessor keywords for defining visibility, hide your class privates with 'private' and so on.
Definitely nothing wrong with object passing. If you have a ClassB object that needs an instantiated object of ClassA in order to function, then your only options are to create that ClassA object inside ClassB, or to pass ClassA in.
If the ClassA object is likely to be used by multiple ClassB objects, like in your example, then passing the ClassA (ie. Database connection object) around is actually more efficient than the alternative, which would involve a lot of duplicate objects being created inside each class.
Since PHP5 automatically passes objects by reference, setting up a reference inside your secondary class to $mainObj is actually very efficient.
One this you'll have to be careful with, with that solution of keeping an object accessing the DB (which is not bad ; you should read about the "Dependancy injection" pattern, btw), is to not disconnect from the DB as long as you still need to be able to access it
(Yeah, seems pretty logical ^^ )
What I mean is it might become easy to forget that some object somewhere needs the DB connection not to be closed.
Easy way would be to never disconnect -- PHP will automatically close the connection to the DB server at the end of the script, anyway.
Not only is this ok, but it's actually one of the cornerstones of OOP, and it's called aggregation
Related
I am testing a class, let's call it ClassUnderTest using another class, let's call it OtherClass. In my Test I do:
$OtherClassStub = $this->createStub(OtherClass::class);
$OtherClassStub->method(...)
->willReturn(...);
$ClassUnderTest->otherClass = $OtherClassStub;
That works. But when the $ClassUnderTest calls new OtherClass(), the original OtherClass class is created instead of the stub.
How can I achieve that every possible instance of OtherClass in the context of the test is replaced by the stub?
From your description I infer that in principle you have something like this:
class OtherClass {
protected function someMethod(): bool
{
// determine $x ...
return $x;
}
}
class ClassUnderTest {
public OtherClass $otherClass;
public function methodToBeTested(): bool
{
$otherClass = new OtherClass();
return $otherClass->someMethod();
}
}
class ClassUnderTestTest extends TestCase {
public function testMethodToBeTested(): void
{
$otherClassStub = $this->createStub(OtherClass::class);
$otherClassStub->method('someMethod')
->willReturn(true);
$classUnderTest = new ClassUnderTest();
$classUnderTest->otherClass = $otherClassStub;
$result = $classUnderTest->methodToBeTested();
$this->assertTrue($result);
}
}
Now the assertion in your test may hold or it may fail. Why? Because you are not calling the method you stubbed on the $otherClassStub. Instead you instantiate a new $otherClass object in the method you're testing (or somewhere down the line).
Either your ClassUnderTest should always use the OtherClass object from the ClassUndertTest::otherClass attribute (assuming that's why you put it there in the first place).
Or you could use some other form of dependency injection, e.g. by using a framework like Symfony or Laravel. (In the case of Symfony you can even use only the DependencyInjection Component, no idea if that's possible with Laravel, too.)
The simple answer to your actual question is: you cannot change the behaviour of the new keyword. Calling new on a class will always instantiate a new object based on exactly that class, unless the constructor of that class defines something else.
(You might want to get the concept of classes and objects straight, your code example as well as your question seem to indicate that you're not quite clear on that. Maybe reading up on that as well as on the concept of dependency injection will help you.)
Perhaps a solution to your problem is presented here:
How to Build a PHP Plugin Module System
This is one way to load classes as plugins and they can be called from each other. With modifying this system a bit, you can create as many "new OtherClass()" as you like from your code and still access everything from other classes. If you want multiple instances of a class, perhaps modify it into this direction:
function load ($module,$instance) {
if (isset($this->$module->$instance)) { return true; }
From above link:
<?php
class Core {
// (A) PROPERTIES
public $error = ""; // LAST ERROR MESSAGE
public $pdo = null; // DATABASE CONNECTION
public $stmt = null; // SQL STATEMENT
public $lastID = null; // LAST INSERT/UPDATE ID
// (B) LOAD SPECIFIED MODULE
// $module : module to load
function load ($module) {
// (B1) CHECK IF MODULE IS ALREADY LOADED
if (isset($this->$module)) { return true; }
// (B2) EXTEND MODULE ON CORE OBJECT
$file = PATH_LIB . "LIB-$module.php";
if (file_exists($file)) {
require $file;
$this->$module = new $module();
// EVIL POINTER - ALLOW OBJECTS TO ACCESS EACH OTHER
$this->$module->core =& $this;
$this->$module->error =& $this->error;
$this->$module->pdo =& $this->pdo;
$this->$module->stmt =& $this->stmt;
return true;
} else {
$this->error = "$file not found!";
return false;
}
}
}
ps. thank you for the mod, who made me work a bit more to keep this answer online. the answer is so much better now.
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.
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.
EDIT: I got this working now. I have updated the code:
I've looked at a few examples in here, and they all look logical. But I can't get it to work. I have a class that extends my Data Access Layer (DAL). I would like to call parent class to retrieve DB results. What am I doig wrong?
DAL class
class DAL {
protected $username; // the username for db connect
protected $pwd; // the pwd to use when connecting
protected $host; // the host to which one connects
protected $dbname; // the db to select
public $conn; // reference to the db link resource
public $db; // result of db_select
public $query_result; // the stored result of the last query you ran
public function __construct()
{
$this->username = "";
$this->pwd = "";
$this->host = "";
$this->dbname = "";
}
public function connect()
{
/* connects to DB here */
}
private function query($sql)
{
/* Executes the query here and stores the result in $this->query_result */
}
public function getAllCountries()
{
$sql ="
SELECT id, name
FROM country";
//Process query
$this->query($sql);
if($this->query_result)
return $this->query_result;
}
}
And this is my other class
class myOtherClass extends DAL{
public function __construct() {
parent::__construct();
parent::connect();
}
public function getCountryListBox()
{
$result = parent::getAllCountries();
if($result)
{
$selectbox = "<select id='countryListBox' name='countryListBox'>";
while ($row = mysql_fetch_array($result))
{
$selectbox .= "<option value='".($row['id'])."'>".($row['name'])."</option>";
}
$selectbox .= "</select>";
}
else
$selectbox = "Countries could not be retrievd from database.";
return $selectbox;
}
}
This is the code in my template:
$sl = new myOtherClass();
echo '<form id="label_data_form">';
$sl->getCountryListBox();
echo '</form>';
The difference between these:
// $result = parent::getAllCountries(); // Like this
$result = this->getAllCountries(); // Or like this?
.. is probably best explained here:
class SuperFoo {
function fubar () {
echo "superfoo!";
}
function fuz () {
echo "superfuz!";
}
}
class SubBar extends SuperFoo {
function fubar() {
echo "subbar!";
}
function demonstrate() {
$this->fubar(); // "subbar!"
parent::fubar(); // "superfoo!"
$this->fuz(); // "superfuz!"
parent::fuz(); // "superfuz!"
}
}
$s = new SubBar();
$s->demonstrate();
(okay, maybe not best explained..)
Unless you particularly want the behaviour defined in the parent class, I'd always use $this->... since then you have the option of altering the behaviour if needed.
The MySQL error seems to be caused by a problem with your SQL - the class inheritance looks to be working fine.
if your class 'myOtherClass' does not implement the 'getAllCountries()' method, the following should work:
$result = $this->getAllCountries();
do not forget the $-sign before 'this'!
for the part you want to fetch list of all countries:
// $result = parent::getAllCountries(); // Like this
$result = $this->getAllCountries(); // Or like this?
the second line is correct. getAllCountries() is a method of your object, because it is inherited from your parent class. so you do not need to call the parent method. one place that you would want to call class parent's methods are in methods where you are overwriting the method.
anyways I suggest you define your properties in your DAL class as 'protected' instead of 'private'. because when you define them 'private', they can not be inherited.
so in your DAL class:
protected $username; // the username for db connect
protected $pwd; // the pwd to use when connecting
protected $host; // the host to which one connects
protected $dbname; // the db to select
you should define those properties as private, only if you do not want them to be inherited. I think your new object needs these info to connect to database.
Steven, let me draw your attention to other things, that are incorrect in your sample despite being syntactically correct. The major issue here is responsibility separation: Data Access Layer should only act as a general purpose data retrieving/storing utility class. Any additional logic should be moved outside this class.
Database connection handling should not be part of DAL. Ideal solution is to pass the db object in constructor, so the DAL operates on the connection configured somewhere else. This is called Dependency Injection and is generally regarded a good thing.
Method getAllCountries is way too specific for general purpose library. Should be replaced with getAll returning all records from current table. Table name should be passed in constructor or defined in subclass, so that every table has its corresponding DAL object.
*Method getCountryListBox generates some HTML output, which is not part of responsibility of DAL library. DAL should only return raw data.
It is worth keeping things separated, so you can reuse them in the future. Adding too many problem specific extension blurs the responsibility of a class. Main objectives of a class should be very narrow-minded, so classes can specialise in doing different things. Cooperation between several highly specialised classes should be the way of delivering complex functionality.
Generally speaking, you would use
$result = $this->getAllCountries();
(Note the **$**this rather than this!)
When calling getAllCountries from anywhere other than the getAllCountries method itself. This will ensure that if you were to override it, the overriden method would be called.
Inside the method, if you wanted to call the base class version, you would need to disambiguate the call with parent::
parent::getAllCountries();
Note you can use this form of method call within any method, but I would argue that it would be bad practice to do this by default, since it denies you the opportunity to override that method later on.
Answer to you edit?
Another typo:
but I guess you have this correct (-> in stead of -) in your code.
Are you sure the 'myOtherClass' is the 'storelocator' class?
Are you sure that storelocator is an instance of MyOtherClass? Because the method you are calling, getCountryListBox is defined in MyOtherClass, and the error complains about an undefined methods getCountryListBox...
<?php $sl = new storelocator(); ?>
<form id="label_data_form">
<?php $sl->getCountryListBox(); ?>
Update
You should add error handling logic inside query() and getAllCountries().
this->getAllCountries(); should be fine, provided that it was a type and you actually meant $this, ie with a dollar.
I'd also like to point out missing logic in getAllCountries() for cases when the query() method is returning nothing and thus $this->query_result holds nothing. getAllCountries() should return something like an empty array, because there may be cases when there's not country in the DB. You want to be able to handle that.
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.