0

I'm determined to get a decent answer to this, because while I have my own approach (constants) I'm not convinced I'm doing it as efficiently as I could be.

So I'm editing the entire question, to add actual code for a more clear description, and am adding a bounty (as much as I can).

(Sorry Ixrec, your answer might not stand any more).

Basic overview of my (simple) framework

  1. htaccess sends all requests to Front Controller (index.php)
  2. Front Controller loads Bootstrap.php
  3. Bootstrap loads all other framework things - e.g. Error reporting setup; Auto loading; PHP Version check; Router;

Problem

I'm stuck at deciding on the best way to store "simple data" that's used throughout the framework. Some used 3-4 times, some only once (at the moment).

Simple data is things like: PHP Version Running; Minimum PHP Version framework requires to operate; Allowed characters in the URI; Framework data (name, support contact details);

While arrays and constants are simple and affective, they instantly pollute the global space, and constants do so indefinitely (end of stack).

Classes seems good approach in terms of data is only called where needed, and so global space is not just immediately polluted with all data.
However, a class to just store some small data seems over kill (i.e. "5.4.0").

So I am conflicted with what option to choose, as all have pros and cons.
I can choose, but wanted some feedback from more seasoned devs.

Requirements

1)
Data to be re-usable.
Not all, but most data will likely be used in multiple classes/files/templates (or at least want it open for future possibilities).

2)
Avoid over polluting global data as much as possible (i.e. just including a file with 50 data items in an array or 50 constants).

While the data needs to be re-usable, and so global (i.e. constants) is the easiest option, I am trying to avoid just shoving it all into global instantly.

I also feel it's best to keep all this data as one type, ie ALL in an array, or ALL in constants, and all in one place - making it easy to manage.

But if that is not the best approach do say - remember while it is different data for different components, so arguably some could be in classes, some array, some constants etc, they have a common ground in that they are ALL simple data. So whatever option is best it will be likely be best for all this data.

Examples/Options

I have a "PHP Version Check", which is a class loaded early on in Bootstrap which checks if the running (server) PHP version is adequate for what the framework requires to operate.

So using the data required for that component as an example of the data problem I face:

NOTE: There are currently about 50 data items. The examples below only have one data item, which makes it appear as if the issues don't matter, especially polluting global space (the total data items will likely also grow in the future).


OPTION 1 - ARRAY

$ConfigArray['phpVersionRunning'] = PHP_VERSION;
$ConfigArray['phpVersionRequired'] = '5.4.0';

PROS
Data will be in a single array, a simple approach.

CONS
Data is immediately pushed into global.
Data can be altered.
Array name and array index name being long enough to be descriptive means long code in other files where this data is needed.
e.g. if ( $ConfigArray['phpVersionRequired'] !== $ConfigArray['phpVersionRunning'] )


OPTION 2 - CONSTANTS

define ('PHP_VERSION_RUNNING', PHP_VERSION);
define ('PHP_VERSION_REQUIRED', '5.4.0');

PROS
This is the most simple and clean looking approach, where used in other files constants are clear in their purpose etc.
e.g. if ( PHP_VERSION_RUNNING !== PHP_VERSION_REQUIRED )
Instantly accessible wherever needed, including in classes.
Data cannot be altered.

CONS
They are all pushed into global instantly.
They remain in global right through Front End, controllers, templates, view, etc, and won't be needed by them.


OPTION 3 - CLASS

class PhpVersionData
  {

    private $VersionRunning;
    private $VersionRequired;

    protected function __construct()
      {
        $this->VersionRunning = PHP_VERSION;
        $this->VersionRequired = '5.4.0';
      }

    protected function getVersionRunning()
      {
        return $this->VersionRunning;
      }

    protected function getVersionRequired()
      {
        return $this->VersionRequired;
      }

  }

PROS
Data is only created at the first point where it's needed.

CONS
Firstly, this just looks way OTT for just basic data.
Constructor and Methods can be protected, so class would need extending so not instantly polluting global space, but then am treading into singleton territory and also tight coupling (?).
If public methods/constructor instead, then am back to potential global pollution issue.


OPTION 4 - Separate data loading:

Another approach is to use constants, or array or variables, but stored in separate files. So each file could be included separately and only when needed.
This avoids everything being immediately in global space, and with array/constant I could unset them once they are no longer needed.
On paper, this sounds like a great idea, but in practice it seems very fiddly, and maintaining it would be harder as data is stored and called all over the place.

Summary

They all have pros and cons which conflict each other. While one option seems ideal, such as constants, it has a major con which pollutes global space indefinitely.

In honesty, I'm swayed to a config array, as although it is pushed into global from the start, I can clean it up at points in the stack where it's no longer needed.

But there are pros and cons to all approaches, and would like to know what is the most robust approach juggling global space pollution, maintainability, ease of use/readability, etc.

  • The question is being discussed on Meta. – Arseni Mourzenko Mar 1 '15 at 14:16
  • @MainMa I cannot comment in the meta discussion as I do not have 5 rep – James Mar 1 '15 at 15:15
  • I just gave you a rep bump. – MetaFight Mar 1 '15 at 15:17
  • @MetaFight most kind. If you want to remove the upvote, LMK and I'll edit the question (tentatively..). – James Mar 1 '15 at 15:26
  • Before answering, I'd like to know if you're really this concerned with just a few things you'd need to store for sanity checking at boostrap, or if perhaps you're working on something where it's quite a bit more than a few things? If you're just looking at PHP runtime and refusing to run if things aren't what you need, then you're probably micro-optimizing. If you're needing to make a lot of choices based on these values, that's another. You've given version as an example, is that really all there is to this? That matters for an answer. – Tim Post Mar 1 '15 at 16:57
3
+100

I don't particularly care for any of your proposed approaches simply because it's tying your classes directly to your configuration. Which means that once you do decide on an approach then you are pretty much stuck with it.

Instead, you should consider adopting more of a dependency injection approach.

class Bootstrap
{
    public function __construct($phpVersionRequired)
    {
        if (version_compare(PHP_VERSION, $phpVersionRequired) < 0) {

The point being is that your actual code neither knows nor cares where $phpVersionRequired comes from. Your question talks about global data and global accessibility but you don't really want that.

Of course whomever creates the Bootstrap object needs to know where $phpVersionRequired comes from. There raises the question of what do you mean by "simple framework". Like @Ixrec has suggested, you best bet might be to look at some existing solutions. If your simple framework includes a dependency injection container then most of the injection stuff can be abstracted away.

The Silex micro-framework (http://silex.sensiolabs.org/) might be a good starting point. The Symfony 2 framework (http://symfony.com/doc/current/reference/index.html) represents the other end of the spectrum.

What is relevant is that both use the same Symfony\Config component (http://symfony.com/doc/current/components/config/introduction.html).

So maybe spend some time researching existing solutions and perhaps rethink this global approach to locating dependencies. Inject your dependencies instead of trying to pull them out of some global resource.

===========================================================

Update 06 Mar 2015

So the question appears to be about where to actually store the config options and how to access them. My answer is to use a dependency injection container. In PHP, Pimple is a simple and widely used container: http://pimple.sensiolabs.org/

use Pimple\Container;

$container = new Container();

// Here is a config parameter
$container['php_version_required'] = '5.5.5';

// Here is a service definition which injects the above parameter
$container['bootstrap'] = function ($c) {
    return new Bootstrap($c['php_version_required']);
};

// Here we get our bootstrap object with it's dependency injected
$bootstrap = $container['bootstrap'];
$bootstrap->run();

Of course you will probably want to read the values of your config options from some sort of parameter file but the values themselves would be saved in your container. The more advanced Symfony 2 container (http://symfony.com/doc/current/components/dependency_injection/introduction.html) has additional support for reading config files as well as caching for improved performance.

  • Thanks. I agree with your points, including "tying classes directly to config" and "you don't want global data/global accessibility", hence my question/problem. I understand your class example, but currently my components which use the data do not know or care where it comes from. My main issue is "where and how to set data" (ie class, array, constant, function, ini file, etc) so not sure how DI resolves the locale of the data? I've looked at other frameworks a bit, but their requirements are very different to mine as they are complex systems. They use various methods for different scenarios. – James Mar 1 '15 at 16:43
  • Would probably +1 if I could figure out whether this answer is appropriate for whatever the question is or is not supposed to be right now. – Ixrec Mar 1 '15 at 20:53
  • Yep. I know the feeling. – Cerad Mar 1 '15 at 21:29
  • @James - Just updated my answer. Not sure if you get notifications for updates or not. – Cerad Mar 6 '15 at 21:11
  • Thanks for the additional info. Defo food for thought and a solid direction to investigate, thanks. – James Mar 8 '15 at 20:58
1

If you have enough of these little configuration values that you feel the need to put them in another file, then they should go in a configuration file, not a source code file. There are countless ways of implementing config files, but I believe PHP has some standard approaches.

To answer your numbered questions more directly:

1) They're never really "necessary", but they're definitely useful once you have a lot of data. But again, they should be actual data files, not just code files that contain object literals.

2) A class whose sole purpose is to provide access to these values is not so good. But a class whose sole purpose is to parse config files is perfectly fine (and you'll typically get this from a library).

3) I believe the link I gave above is a good place to start.

  • Thanks for the advice and info. I thought ini config is more for "hardcore" config settings, rather than basic application/system data? I'll do some more reading however. Thanks – James Feb 27 '15 at 2:42
  • .ini is a very simple format, nothing hardcore about it. I think it gets that reputation from when end users have to dive into an app's .ini file to change things the app fails to provide a settings screen for. – Ixrec Feb 27 '15 at 9:56
  • @lxrec - I've changed my entire question, and added a bounty (just letting you know as I don't think you'll be pinged otherwise) – James Mar 1 '15 at 13:57
  • @James, it might be better to leave this question in original form and simply ask a new one. – MetaFight Mar 1 '15 at 14:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.