views:

558

answers:

5

I have some PHP code similar to the following:

foreach ($settingsarray as $settingsfile)
{
    include ($settingsfile);
    // do stuff here
}

$settingsarray is an array of file names from a particular folder.

The problem is, that each $settingsfile defines constants (with the same names), which of course, can not be redefined.

What possible methods are there to prevent errors occurring in this situation?

Two options I can think of include, changing all the constants to variables and using PHP namespaces.

However, I'm not sure how I would go about using namespaces, it would require the declaration at the start of every $settingsfile? Is there a method of isolating constants, ariables and functions without using namespaces?

What I would really love, is to be able to do something as simple as:

foreach ($settingsarray as $settingsfile)
{
    {//added braces to indicate where the isolation is
     include ($settingsfile);
     // do stuff here
    }//what happens in here does not affect what happens outside of here
}

I should just note, this is part of a new feature, and is the only part of the code that loads all the $settingsfiles. The rest of the code only ever loads one file at a time. One reason I am using constants is so that I don't have to worry about defining variables "global" to be able to access them inside functions.

+1  A: 

Okay, so if I'm understanding you correctly, inside that loop you'd like to do things with the constants defined inside each $settingsfile and then basically get rid of them after each loop?

Unlike variables, a constant is a value that, once set, cannot be changed or unset during the execution of your script src

Your only option is to change the define() declarations to variables.

nickf
You got what I want to do correctly. The solution, I didn't want to hear. (The program is actually quite complex, and this code is from a new feature. All the rest of the code only ever loads up one of the settings files at a particular time. To change all the constants to variables will mean changing all the rest of the code as well...)
Alya
+1  A: 

not easy but you could read the php file with file_get_contents($settingsfile) then rewrite the constants, and eval the code.

$settingsstr = file_get_contents($settingsfile);
$settingsstr = preg_replace('/<\?\w*(.*)/', '\\1', $settingsstr);//get rid of the php open tag
$settingsstr = preg_replace('/define\("(\w+)"/', 'define("NAMESPACE_\\1"', $settingsstr);
eval($settingsstr);
hayato
this just screams "awful awful hack"
nickf
+1  A: 

You have a few options:

Use PHP Namespaces

Surprisingly, PHP actually does have support for namespaces. I was very surprised to find this since I have been working in PHP for years and have never heard of this feature. It is likely a newer feature and one that is not commonly used, so I would suggest not using this method

Use Class Constants

You could use classes and class constants to load your settings. Class constants are local to the defining class, so you will not need to worry about name collisions within the class. You would probably need to do more than include the file, but you could call a method on each class, such as defineConstants() or loadConfiguration() that would define the application constants, keeping the class constants for internal use.

Use Functions to Extend the Settings

Another idea is to create a settings array and separate functions to 'extend' those settings. That way you can over-write any configuration in subsequent functions without causing an error. Finally, if you want to put those in constants, you could loop over the array and use define() to define the constants.

There are many other ways to accomplish what you are trying to do, but these are just a few ideas.

jonstjohn
namespaces are new in PHP 5.3, but this hasn't been released as stable yet.
nickf
A: 

A settings file should not contan PHP code. It should be some kind of "standard" format. http://www.php.net/parse_ini_file

  • In the first step (in your foreach) you read all files
  • Collect the variables into a temporary array
  • In another loop over this array, you can define them as constants.

If you routinely feel the need to "redefine constants" then something is amish in the application design.

Csaba Kétszeri
I don't think there's anything intrinsically BAD about having settings defined in PHP. I wouldn't want end users ending these settings files, but it's much more efficient for me to write my settings directly in PHP.
nickf
This is the only section of the entire application where I feel the need to redefine constants. Problem is, new feature.
Alya
+1  A: 

My answer is somewhat complex, but should work for you quite nicely. I'm assuming you have a ton of these settings files, since you're so averse to changing each one individually.

If you're able to use namespaces, I'll assume you've already upgraded to PHP 5.3RC2. Copy the following into a .php file, and change the namespace to your liking:

<?php
namespace myapp\config;

function define($key, $val) {
    Config::set($key, $val);
}

class Config {
    private $vars = array();

    // This class should not be instantiated
    private function __construct() {}

    public function set($key, $val) {
        self::$vars[$key] = $val;
    }

    public function get($key) {
        return isset(self::$vars[$key]) ? self::$vars[$key] : NULL;
    }
}

?>

Include that in your code, and now making everything work is a simple matter of changing the

<?php

in your settings files to

<?php namespace myapp\config;

If you have a ton of them, a quick 'sed' command in your terminal should take care of it quite nicely, all in one fell swoop.

If I lost you on how to use my code, here's an example:

<?php
require_once('the_php_file_i_just_gave_you.php');
use \myapp\config\Config;

foreach ($settingsarray as $settingsfile) {
    include ($settingsfile);
    $varname = 'key';
    echo "In this file, '$varname' equals: " . Config::get($varname);
}

?>

Good luck!

Tom Frost