configuration: constants vs singleton pattern

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

tdnxxx444
Forum Newbie
Posts: 23
Joined: Wed Mar 08, 2006 5:57 pm

configuration: constants vs singleton pattern

Post by tdnxxx444 »

I am trying to setup a way to configure my application and I have read various solutions. Seems as though most people prefer to use a singleton class to do this. However, I was also looking at using constants. What would be the pros and cons of each method?
User avatar
Buddha443556
Forum Regular
Posts: 873
Joined: Fri Mar 19, 2004 1:51 pm

Post by Buddha443556 »

If your going for a strictly OO solution then you would lean more towards the singleton. Reason being constants are global and therefore would create dependencies and thus Foobarring your encapsulation. This would not effect a procedural solution as global data is the foundation that holds everything together.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

I guess it depends upon what kind of flexibility you want. Is your application all OOP?

Singletons work better in PHP5 due to the private constraints but there's no reasons you can't do it with PHP4 too, minus the private keyword.

I use a singleton myself. It was mentioned in another thread recently. The advantage to using a class to hold your configuration directives is that you can modify the values under certain conditions. With constants you can't, but perhaos that's a good thing? I see my configurations as a set of defaults to work with, but by no means the be all and end all to the way the app will work.

The great thing with a singleton is that you can modify the values, instantiate it only once and use it anywhere in your app:

Code: Select all

<?php

class configDirectives
{	
	protected

	$username = 'joe',
	$password = 'pass',
	$dummy;

	//Ignore -- This just prevent instantiation
	// although with nothing but protected properties it's useless without methods or a parent
	private function __construct(){}
}

class config extends configDirectives
{
	static private $instance = null;

	private function __construct()
	{
		$this->dummy = 42; //Just a demonstration
	}

	static public function fetch()
	{
		if (self::$instance == null)
		{
			self::$instance = new config();
		}
		return self::$instance;
	}

	public function set($what, $x)
	{
		$this->{$what} = $x;
	}

	public function get($what)
	{
		if (isset($this->{$what})) return $this->{$what};
	}

	public function dump()
	{
		print_r($this);
	}
}

$foo = config::fetch();

$foo->dump();
$foo->set('username', 'someone_else');

$bar = config::fetch();

$bar->dump();

//If we try instantiating the config class directly we get an error
$conf = new configDirectives();

?>
Basically -- Personal choice. Singleton gives you flexibility, constants can;t be changed ;)

EDIT | Changed my silly generic example to something a bit more meaningful. Another point to note is that you can hold your configuration in an XML or INI file that gets read when $instance is created, rather than having these in a class like I do.
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post by alex.barylski »

I'm a hardcore OOP zealot...but I disagree with using classes for everything and anything...

I don't know...perhaps your onto something here with using a singleton...

I'm not sure actually why I disagree with using classes in this instance...

I guess it's because for me...the number one rule of OOP is reusability...if you can't reuse it...don't OOP it. Config settings are not very portable....their kind of application specific...

So the whole 'drop right in' appeal of OOP is kinda stomped on...

I'd personally use a module with GLOBALS and the constant modifier (if you can in PHP) but maybe thats just my old stubborn arse talking...?

Interestingly enough you certainly got me thinking...not sure if I"ll ever change my mind on the subject, but i'll think about it :)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Hockey wrote:I'm a hardcore OOP zealot...but I disagree with using classes for everything and anything...

I don't know...perhaps your onto something here with using a singleton...

I'm not sure actually why I disagree with using classes in this instance...

I guess it's because for me...the number one rule of OOP is reusability...if you can't reuse it...don't OOP it. Config settings are not very portable....their kind of application specific...

So the whole 'drop right in' appeal of OOP is kinda stomped on...

I'd personally use a module with GLOBALS and the constant modifier (if you can in PHP) but maybe thats just my old stubborn arse talking...?

Interestingly enough you certainly got me thinking...not sure if I"ll ever change my mind on the subject, but i'll think about it :)
I respectfully disagree that this is not reusable. Providing you keep your config directives somewhere separate it works the same everywhere. In fact, scrap the "configDirectives" class and have a file called config.xml. Then all you need to do is have the singleton load that file and parse, just the first time you call getInstance() and voila, a whole set of config directives. I picked XML as an example becuase it parses extremely easily and it's flexible. Start chucking globals into your OOP app and how far do you go before you realise your app is getting rather large and you've got more globals than you can handle flying around? -- Start out with the best design you can, you're less likely to kick yourself in the teeth (just how many times did you start writing a "little" app and suddenly you ended up with a large project on the go?) Just my $0.02.
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post by Maugrim_The_Reaper »

Depends on what is re-usable. The actual variables, or the method of importing config values? A singleton can have any number of values in any format - you can changes these whenever you want without altering the Config::fetch() behaviour which itself is entirely re-usable. I suppose it all comes down to whether you need to change the fetch() or singleton style inclusion at will - not just the values and import methods of the Config class.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

The point of using a class rather than constants is that you have an interface. Once you have an interface you can refactor the code behind the interface at will.

Say for example that most of your configuration values are in a config.php file that you edit when you setup the application. But then you want to add some administrative configuration where the user sets values in a database table or maybe an INI file. You can merge all those values into a configuration object, even changing the data source as needed, without having to change any of the application the code that accesses configuration data.
(#10850)
User avatar
Buddha443556
Forum Regular
Posts: 873
Joined: Fri Mar 19, 2004 1:51 pm

Post by Buddha443556 »

arborint wrote:The point of using a class rather than constants is that you have an interface. Once you have an interface you can refactor the code behind the interface at will.

Say for example that most of your configuration values are in a config.php file that you edit when you setup the application. But then you want to add some administrative configuration where the user sets values in a database table or maybe an INI file. You can merge all those values into a configuration object, even changing the data source as needed, without having to change any of the application the code that accesses configuration data.
Be sure to follow the Open-Close Principle it will make your OO life easier.

Open-Close Principle

You may also want to look up other principles of Object-Oriented Design such the Interface Segregation Principle.
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post by alex.barylski »

d11wtq wrote:
Hockey wrote:I'm a hardcore OOP zealot...but I disagree with using classes for everything and anything...

I don't know...perhaps your onto something here with using a singleton...

I'm not sure actually why I disagree with using classes in this instance...

I guess it's because for me...the number one rule of OOP is reusability...if you can't reuse it...don't OOP it. Config settings are not very portable....their kind of application specific...

So the whole 'drop right in' appeal of OOP is kinda stomped on...

I'd personally use a module with GLOBALS and the constant modifier (if you can in PHP) but maybe thats just my old stubborn arse talking...?

Interestingly enough you certainly got me thinking...not sure if I"ll ever change my mind on the subject, but i'll think about it :)
I respectfully disagree that this is not reusable. Providing you keep your config directives somewhere separate it works the same everywhere. In fact, scrap the "configDirectives" class and have a file called config.xml. Then all you need to do is have the singleton load that file and parse, just the first time you call getInstance() and voila, a whole set of config directives. I picked XML as an example becuase it parses extremely easily and it's flexible. Start chucking globals into your OOP app and how far do you go before you realise your app is getting rather large and you've got more globals than you can handle flying around? -- Start out with the best design you can, you're less likely to kick yourself in the teeth (just how many times did you start writing a "little" app and suddenly you ended up with a large project on the go?) Just my $0.02.
Edit: After some more thought, I'm not sure I agree 100% with myself even...it's a tough call...I still say classes aren't the right solution for config data, but they do a slightly better job ensuring that data isn't misused or abused than straight GLOBALS do (although if the const modifier was available that problem would be solved).
/Edit:

I can't disagree...neither is really re-usable though. Seeing how config settings are app sepcific. Perhaps my problem comes in with accessing a classes properties directly, but I still disagree with using classes in this instance. If your using accessors/mutators IMHO your already gone way to far in abusing what classes are intended for.

As for experiencing problems with GLOBALS I can honestly say I have never encountered a problem with using GLOBALS. In PHP I use a pretty lengthly naming strategy which dissuades re-assignment at runtime.

A class (in my opinion) should be re-usable and offer the opportunity for derivation, inheritance, etc...encapsulation is important I agree and the additional namespace protection is nice too, but still.

Consider a simple wrapper class, which does little but offer an OOP API around a library of functions.

As an example lets say: CString which encompasses all of the string manipulation functions PHP has to offer (or any language)

Although it likely doesn't derive from any object, nor will it likely be used as a base class, it still supports the following:

1) Reusablility
2) Encapsulation

Now i'm not even sure where I'm going with this...maybe i'm arguing for the sake of arguing :P

My 2 biggest problems with using classes in this situation are:

1) Reusability - This is number ONE (for me personally) when designing a class.
2) There is a difference between being an OOP zealot and and OOP fanatic. You "could" use classes for everything, but often you end up going beyond the original intended use. For example, you could use PHP classes like:

Code: Select all

class myView{
  function showHeader($title)
  {
     echo '<head><title>'.$title.'</title><script src="test.js"></script></head>';
  }
}
This is valid syntactically, but OOP friendly? No! it breaks the number one golden rule of re-usability.

Templates are a much better solution.

You could implement an entire class which parses source code, but it makes for alot cleaner code using EBNF and a parsing framework.

My point being, sure classes are awesome, but their intended for a very specific purpose and solving a certain set of problems. Config data isn't one of them IMHO.

Using interspersed techniques (instead of JUST classes) also helps in managing large code bases. Instead of storing image data in classes, obviously you store it in their native format on the HDD or maybe in a database, the point is, when you need that image, you know exactly where to get it and your not stuck sifting through 100's of classes trying to find that image config class.

I've listed all my concerns with using classes as a config solution and thats that :roll: I promise I will not critique or question any methods any more - at least with this topic (i'll try not to anyways) :)
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Buddha443556 wrote:Be sure to follow the Open-Close Principle it will make your OO life easier.

Open-Close Principle

You may also want to look up other principles of Object-Oriented Design such the Interface Segregation Principle.
Excellent point. An implementation like the following would allow you to move config data between data sources and still maintain a single interface for your application:

Code: Select all

$config = new Config($ConfigArray);
$config->merge(config_xml_reader('config.xml'));
$config->merge(config_ini_reader('config.ini'));
$config->merge(config_db_reader($connection, 'config'));
This leads to a couple of question for tdnxxx444, because resorting to globals is a sign that there is something wrong with your design. Why do you need data that can be accessed anywhere in you application? What code really needs this data? What other ways can you get this data to the code that uses it? Is this data read-only or read-write?

And we have not even touched upon the whole "Singletons are Evil" attitude that seems to have taken hold in the last few years. Do a search and you will find more about the pervailing thought. I don't use Singletons, but that is a design choice not a religious one.
(#10850)
tdnxxx444
Forum Newbie
Posts: 23
Joined: Wed Mar 08, 2006 5:57 pm

Post by tdnxxx444 »

arborint wrote:This leads to a couple of question for tdnxxx444, because resorting to globals is a sign that there is something wrong with your design. Why do you need data that can be accessed anywhere in you application? What code really needs this data? What other ways can you get this data to the code that uses it? Is this data read-only or read-write?
I am basically setting up two servers for my development environment -- a staging server and a production server. These servers are going to have areas where the data used by the application are different, such as:

1. Paths - for includes, etc.
2. URLs - for header redirects.
3. Database access information
4. Debugging information -- whether error messages are displayed, is logging turned on etc.

So basically, the data in read-write. Also, I'm not necessarily considering, globals, but constants, which are a little more secure as in you can't modify their values.
tdnxxx444
Forum Newbie
Posts: 23
Joined: Wed Mar 08, 2006 5:57 pm

Post by tdnxxx444 »

d11wtq wrote: The great thing with a singleton is that you can modify the values, instantiate it only once and use it anywhere in your app:

Code: Select all

<?php

$foo = config::fetch();
$foo->set('username', 'someone_else');


?>
What do you mean by this statement? Wouldn't I have to still do:

$foo = config::fetch()

wherever I want to use it again, i.e. in a function?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

tdnxxx444 wrote:
d11wtq wrote: The great thing with a singleton is that you can modify the values, instantiate it only once and use it anywhere in your app:

Code: Select all

<?php

$foo = config::fetch();
$foo->set('username', 'someone_else');


?>
What do you mean by this statement? Wouldn't I have to still do:

$foo = config::fetch()

wherever I want to use it again, i.e. in a function?
I was referring more to the fact that a singleton is always the same object, it's never recreated but in any case what you're saying is partially true but if you used a registry to store an instance of that object you could include it in your object hierarchy and refer to $this->config->username for example.

I posted an brief example in this thread (you'll of course need to substitute the db class with your config class):

viewtopic.php?p=245454#245454
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

tdnxxx444 wrote:I am basically setting up two servers for my development environment -- a staging server and a production server. These servers are going to have areas where the data used by the application are different, such as:

1. Paths - for includes, etc.
2. URLs - for header redirects.
3. Database access information
4. Debugging information -- whether error messages are displayed, is logging turned on etc.

So basically, the data in read-write. Also, I'm not necessarily considering, globals, but constants, which are a little more secure as in you can't modify their values.
I just use separate config.php files that define an array that I pass to the Config object. But I do have a couple of cases where I get config data from a DB as well. I make the Config object available the to application via a Registry/ServiceLocator.

The good thing about a Config object is that you can control how you want to handle write and overwrite conditions.
(#10850)
adiian
Forum Newbie
Posts: 2
Joined: Sat Sep 09, 2006 12:06 pm

Post by adiian »

I think singleton is evil. From the oop perspective. Can not be derived and if you want just to replace the class you have to chanage all the references in the text.
http://www.oodesign.com/oo_design_patte ... leton.html

And php is not a language with a good support for oop and design patterns. I would go for the configuration file in php. Otherwise, if using something like java or c#, I would chose singleton.
Locked