I am working on the largest individual project I have ever worked on - one reason was to learn how the application evolved from a small non-object-oriented project to a massive one that is object-oriented by necessity, and get a more thorough understanding of why different applications necessitate certain architectures.
I originally thought the best way to handle global-scope variables would be to maintain one monolithic class instantiating all of these vars.
class publicValues {
public static $globalBoolean = false;
.
.
public static $globalCounter = 0; // roughly 600 variables total at this point
}
The idea was to keep all global-scope variables "atomic", but I have run into uncertainty with non-static arrays. (will demonstrate with a dummy example below)
public static $allAmericanStates = array('Alaska', .....); // atomic array including all states in the U.S.
public static $allCanadianProvinces = array('Alberta',.....); // atomic array including all provinces in Canada
//here's the problem
public static $allAmericanStates_UNION_allCanadianProvinces = array_merge($allCanadianProvinces, $allAmericanStates); // CAN'T DO THIS
So my solution was to initialize the unions (array_merge
), intersections (array_intersection
), subtractions (array_diff
), implosions, etc. as public static vars (in the class publicValues, see first code block above):
public static $allAmericanStates_UNION_allCanadianProvinces = '';
and subsequently call a function to perform the relevant operations on the atomic arrays (overwriting the empty string value they were initialized as):
function synthesize_remaining_static_vars() {
publicValues::$allAmericanStates_UNION_allCanadianProvinces = array_merge($allCanadianProvinces, $allAmericanStates); // so if California secedes I only need to remove CA from publicValues::$allAmericanStates
publicValues::$implodedAllAmericanStates = implode("|", publicValues::$allAmericanStates); // e.g., for use in preg_match()
//etc.
}
So this way all the global-scope vars can be initiated in one location, and whenever necessary, they can be accessed using 1 class (e.g., publicValues, instead of multiple classes where non-static vars are referenced using a different class). Furthermore, unions, intersections, etc., need not be maintained because they are just the resultant of operations on the atomic arrays.
This may be an opinion question so I apologize if so. Does anyone see any serious issues with the approach of using one publicly accessible class to hold all global-scope variables? (wrt Code Maintainability, "future-proofing", etc.)
What you're describing is a singleton: https://en.wikipedia.org/wiki/Singleton_pattern
I recommend reading up on design patterns to see the pros and cons of the singleton pattern. Having global variables spread out across many classes doesn't mitigate the cons of having global variables, so in this case, if you must have global variables, a singleton to handle them may be a good idea. As for your merge and intersection variables, those could either be initialized in the singleton's __construct and accessed through getters, or through a static function that returns the result of the merge.
My recommendation would be to use a database for this (e.g. SQLite) as this is essentially what you're trying to emulate.
While I have had a few projects which contained monolithic static registries like this, maintenance eventually becomes unrealistic - especially with ~600 variables.
A proper database setup will also cache intermediate results - like what you're trying to do with $allAmericanStates_UNION_allCanadianProvinces
. For this, you should read up on stored procedures. This way, you can delegate all of the optimisation to the database provider and retrieve the data with a standard command as and when you need it.
I often have a singleton helper class to abstract the database commands away from the code for simple retrievals.