Conventions/code/patterns/config

From Woozle Writes Code
< Conventions‎ | code‎ | patterns
Revision as of 16:37, 5 October 2023 by Woozle (talk | contribs) (Created page with "I mainly use classes for storing static configuration data – unlike what Laravel does with array-per-file in a config folder, or what MediaWiki does with LocalSettings.php and global variables. This has multiple benefits, of which the main one is probably that you don't need any special loading mechanism and can refer to a config item from anywhere by invoking the class. Another is that you can set up abstract methods for things that need to be filled in b...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

I mainly use classes for storing static configuration data – unlike what Laravel does with array-per-file in a config folder, or what MediaWiki does with LocalSettings.php and global variables.

This has multiple benefits, of which the main one is probably that you don't need any special loading mechanism and can refer to a config item from anywhere by invoking the class. Another is that you can set up abstract methods for things that need to be filled in by specific apps or deployment, providing automatic cues as to what is missing.

There are two main ways to set this up:

  • as a dynamic class with a singleton-access method, or...
  • as a static class, where you just access the params directly like Config::ParamName().

The static method is easier on the brain, but it doesn't gracefully accommodate local configurability. Although static methods can be virtual, you can't just invoke a virtual static method (or any static class method which invokes a virtual static method) from the base class; you have to specify which class is actually going to be used. This is fine for application code, but library code shouldn't have to know this. The only workaround I can see involves having the class internally store the name of the descendant class-to-use (CTU), and then you're not only back to needing some kind of internal redirector (e.g. "Me()" could return the CTU and then the caller could add "::[method name]()" to invoke the proper static method, but you also have to figure out to save the CTU without a constructor.

Using a dynamic class, on the other hand, means that the endcoder can call their config classes whatever they want (or even have multiple alternates for different situations), as long as they make sure to instantiate the classes they want to actually use before any other code needs to access configs. The endcoder's config-object then becomes ::Me(), which is what all the other code refers to for the actual config methods.

At least a couple of times now, I've initially set up config classes as entirely static, then had to convert to dynamic singleton. When this happens, it may be worth considering whether the class is trying to serve two different areas of function – one that doesn't need for descendant classes to do much reconfiguring, and another that does.