Posted: Fri Dec 14, 2007 3:45 am
scottayy - the deep end is where all the fun in arguing is
.
Don't be discouraged if a simple topic goes off the cliff. The problem with OOP is that if you've never used it before, it takes a bit of time before it makes sense, then a little more time before you understand how all the practices (e.g. encapsulation/decoupling) fit together. You think I was running around preaching OOP when I started? It took me a long time to figure things out - you have the benefit of a forum where everyone can talk it to death
.
I think what's missing from the thread, from a starter's perspective, is why we'd make certain choices. I bet throwing out "encapsulation" and "coupling" and "Registry Pattern" isn't helping here unless we explain it properly. For that you have my apologies.
If the Registry looks useful (I use it a lot, esp. in application code) I wrote an article for that pattern over on:
http://www.patternsforphp.com/wiki/Registry
Let me know if the article is useful.
To offer a concrete example. Your approach depends on whether the code needing the configuration is a) application specific or b) generally reusable. The difference is that application code tends to be less reusable between applications and so using "global" like constructs like functions, Singletons, and Registries have less of a maintenance cost. That's a rule of thumb rather than a hard fact. In such code, and using the PFP article code:
The above can be placed in a central include file so that it's loaded very early for every request to the app. I call this sort of setup script a "bootstrap" file.
Next is getting classes to access the Settings. Say you have a class to create a database connections (whether an abstraction layer, or Model, or whatever:
Now if you wanted to get even more concerned, when you're more comfortable with OOP. You could note that the Database class is coupled to the Registry class. What this means is asking the question - what if I reuse Database in an application where there's no Registry? With one class, you could do a little edit maybe, but usually you could have numerous classes all referring to the same class - that's a lot of editing, and there's no way of maintaining a single central version. This is a bad for a few reasons - if you fix a bug in one edited version, you have to fix it manually in all the others.
One way of escaping this, is using the Factory Pattern. Which you can read about here:
http://www.patternsforphp.com/wiki/Factory
What this does, is make a little shuffle and move the Registry reference in Scottayy_Database to a separate class. I'll show the potential Database code first:
The difference here is that Database now has no clue Registry exists (we can move it to new apps safely that have no Registry). Furthermore, the interface has become more general - using a stdClass for settings input. Pretty easy to play with anywhere you reuse it. In fact, this all lets us introduce a class to create Databases called Scottayy_Database_Factory. Bear with me...
The point of the Factory is to manage creating Database classes. Here it allows for a Registry. In another app, you could add support for an array, or a different Registry type, or single value params, or... Without a Factory to play with, you'd need to edit the Database class itself all the time - a Factory is a much smaller, easy to design ad-hoc as needed.
Our previous bootstrap code could be amended (if we include database conn here) to:
Note. Most of the time I use OO syntax for Registries/Settings. You could implement both using an array style access method (e.g. $registry['settings'] instead of $registry->settings).
Is this a bit more informative and what would be useful to you?
Don't be discouraged if a simple topic goes off the cliff. The problem with OOP is that if you've never used it before, it takes a bit of time before it makes sense, then a little more time before you understand how all the practices (e.g. encapsulation/decoupling) fit together. You think I was running around preaching OOP when I started? It took me a long time to figure things out - you have the benefit of a forum where everyone can talk it to death
I think what's missing from the thread, from a starter's perspective, is why we'd make certain choices. I bet throwing out "encapsulation" and "coupling" and "Registry Pattern" isn't helping here unless we explain it properly. For that you have my apologies.
If the Registry looks useful (I use it a lot, esp. in application code) I wrote an article for that pattern over on:
http://www.patternsforphp.com/wiki/Registry
Let me know if the article is useful.
To offer a concrete example. Your approach depends on whether the code needing the configuration is a) application specific or b) generally reusable. The difference is that application code tends to be less reusable between applications and so using "global" like constructs like functions, Singletons, and Registries have less of a maintenance cost. That's a rule of thumb rather than a hard fact. In such code, and using the PFP article code:
Code: Select all
// establish a bucket, i.e. Registry
$registry = new Scottayy_Registry;
// get your settings, class just uses parse_ini_file and some setters/getters
// quite a simple class to write - or steal Zend_Config
$settings = new Scottayy_Settings_Ini;
$settings->import('./path/to/settings.ini');
// Add settings to Registry
$registry->settings = $settings;Next is getting classes to access the Settings. Say you have a class to create a database connections (whether an abstraction layer, or Model, or whatever:
Code: Select all
class Scottayy_Database
{
protected $_settings = null;
protected $_conn = null;
public function __construct()
{
$registry = Scottayy_Registry::getInstance(); // Singleton Registry
$this->_settings = $registry->settings;
}
public function connect()
{
$host = $this->_settings->host;
$dbname = $this->_settings->dbname;
$user = $this->_settings->user;
$pass = $this->_settings->password;
$this->_conn = $dbh = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
}
// ...
}One way of escaping this, is using the Factory Pattern. Which you can read about here:
http://www.patternsforphp.com/wiki/Factory
What this does, is make a little shuffle and move the Registry reference in Scottayy_Database to a separate class. I'll show the potential Database code first:
Code: Select all
class Scottayy_Database
{
protected $_settings = null;
protected $_conn = null;
public function __construct(stdClass $settings)
{
$this->_settings = $settings;
}
public function connect()
{
$host = $this->_settings->host;
$dbname = $this->_settings->dbname;
$user = $this->_settings->user;
$pass = $this->_settings->password;
$this->_conn = $dbh = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
}
// ...
}Code: Select all
class Scottayy_Database_Factory
{
public static function createInstance()
{
$args = func_get_args(); // be flexible in how you get input
if ($args[0] instanceof Scottayy_Registry) {
$stdInput = self::_createFromScottayyRegistry($args[0]);
}
$db = new Scottayy_Database($stdInput);
return $db;
}
protected static function _createFromScottayyRegistry(Scottayy_Registry $registry)
{
$stdInput = new stdClass;
$settings = $registry->settings;
$stdInput->host = $settings->host;
$stdInput->dbname = $settings->dbname;
$stdInput->user = $settings->user;
$stdInput->password = $settings->password;
return $stdInput;
}
}Our previous bootstrap code could be amended (if we include database conn here) to:
Code: Select all
// establish a bucket, i.e. Registry
$registry = new Scottayy_Registry;
// get your settings, class just uses parse_ini_file and some setters/getters
// quite a simple class to write - or steal Zend_Config
$settings = new Scottayy_Settings_Ini;
$settings->import('./path/to/settings.ini');
// Add settings to Registry
$registry->settings = $settings;
// create a database connection object (and add to Registry for fun)
$database = Scottayy_Database_Factory::createInstance($registry);
$registry->database = $database;Is this a bit more informative and what would be useful to you?