PHP Classes - global or __construct - php

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.

Related

(php) Better way to use global variables? Or how to avoid them?

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.

database connection is not recognized in my functions [duplicate]

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.

PHP Dependency Injection and Loose Coupling

I am pondering a few different approaches here and would really appreciate some input! I am considering the two choices below. There are 2 things going on there I have questions on.
Is it preferred to inject the dependencies into the constructor of the main "container" class, or to instead create new instances inside the container class?
In the second example, the class' dependencies are injected via constructor and then maintained within via a property of the class. Then when the methods (route(), render()) are called, the dependencies are called from within. I began with this approach, but am now favoring something more along the lines of the first example. I think the first example is preferable, but are there any benefits to using the DI approach in the second example?
There really is no need to store anything in the class as a property. I can probably rearrange everything to use that technique without much trouble, and I think I like it better. This way I can also move all of the of work out of the constructors, and simply access everything via method later. Am I on the right track here?
class App
{
private $config;
private $router;
private $renderer;
public function __construct(IConfig $config, IRouter $router, IRenderer $renderer)
{
$this->config = $config;
$this->router = $router;
$this->renderer = $renderer;
$this->run();
}
public function run()
{
$data = $this->router->route(new Request, $config->routes);
$this->renderer->render($data);
}
}
class App
{
private $config;
private $router;
private $renderer;
public function __construct()
{
$this->config = new Config;
$this->run();
}
public function run()
{
$this->router = new Router(new Request, $config->routes);
$this->router->route();
$this->renderer = new Renderer($this->router->getData());
$this->renderer->render();
}
}
It is better to inject dependencies into the constructor.
Creating instances within the constructor creates a tight coupling between the two classes. With a constructor with a clear signature like
public function __construct(IConfig $config, IRouter $router, IRenderer $renderer)
I can immediately tell what this component needs to do it's job.
Given a constructor like
public function __construct();
There is no clue what the component needs to function. It creates a strong coupling to specific implementations of your each your router, your request and to your renderer, none of which are apparent until you dig down into the guts of your class.
In summary the first approach is well documented, extendable and testable.
the second approach is opaque, highly coupled, and not easily testable.
While Orangepill makes a good point, I thought I'd chip in, too. I tend to define my constructors with a clear constructor, too, but I don't expect the required objects to be passed when creating an instance.
Sometimes, you create an instance that retrieves data either from a DB, or some sort of Http request. In your case, the first example expects three dependencies to be passed, but who's to say that you'll always need all three of them?
Enter Lazy-Loading. The code sample below is quite lengthy, but it is (IMO) well worth looking into. If I use a service, I don't want to load all dependancies unless I'm sure I'll be using them. That's why I defined the constructor so that I can create an instance in either one of the following ways:
$foo = new MyService($configObj);
$bar = new MyService($configObj, null, $dbObj);//don't load curl (yet)
$baz = new MyService($configObj, $curlObj);//don't load db (yet)
If I wanted to run some test, I can still inject the dependencies when constructing my instance, or I can rely on a test-config object or I could use the setDb and setCurl methods, too:
$foo->setCurl($testCurl);
Sticking to the first way of constructing the instance, I can safely say that, if I only invoke the getViaCurl method, the Db class will never be loaded.
The getViaDb method is a bit more elaborate (as is the getDb method). I don't recommend you working with methods like that, but it's just to show you how flexible this approach can be. I can pass an array of parameters to the getViaDb method, which can contain a custom connection. I can also pass a boolean that'll control what I do with that connection (use it for just this one call, or assign the connection to the MyService instance.
I hope this isn't too unclear, but I am rather tired, so I'm not all too good at explaining this stuff ATM.
Here's the code, anyway... it should be pretty self explanatory.
class MyService
{
private $curl = null;
private $db = null;
private $conf = null;
public function __construct(Config $configObj, Curl $curlObj = null, Db $dbObj = null)
{
$this->conf = $configObj;//you'll see why I do need this in a minute
$this->curl = $curlObj;//might be null
$this->db = $dbObj;
}
public function getViaCurl(Something $useful)
{
$curl = $this->getCurl();//<-- this is where the magic happens
return $curl->request($useful);
}
public function getViaDb(array $params)
{
if (isset($params['custom']))
{
$db = $this->getDb($params['custom'], $params['switch']);
}
else
{//default
$db = $this->getDb();
}
return $db->query($params['request']);
}
public function getCurl()
{//return current Curl, or load default if none set
if ($this->curl === null)
{//fallback to default from $this->conf
$this->curl = new Curl($this->conf->getSection('CurlConf'));
}
return $this->curl;
}
public function setCurl(Curl $curlObj)
{//inject after instance is created here
if ($this->curl instanceof Curl)
{//close current connection
$this->curl->close();
}
$this->curl = $curlObj;
}
public function setDb(Db $dbObj)
{
if ($this->db instanceof Db)
{//commit & close
$this->db->commit();
$this->db->close();
}
$this->db = $dbObj;
}
//more elaborate, even:
public function getDb(Db $custom = null, $switch = false)
{
if ($custom && !!$swith === true)
{
$this->setDb($custom);
return $this->db;
}
if ($custom)
{//use custom Db, only this one time
return $custom;
}
if ($this->db === null)
{
$this->db = new Db($this->conf->getSection('Db'));
}
return $this->db;
}
}

Can I make a variable globally visible without having to declare it global in every single PHP class's constructor?

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');

What is the best method for getting a database connection/object into a function in PHP?

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.

Categories