this is more a conceptual question. Consider you have a php framework that runs a generic website.
You can of course tweak the framework behavior with settings, the question is: where is more natural to place these settings?
My framework consists of some functions that helps me doing some tasks (for example cache managment).
In this fw I use a generic variable
$config = array( 'setting1'=>'value1' etc );
And if a function needs it does a global:
function manageCache() {
global $config;
//> perform task with settings from $config
}
Consider the procedural nature of my framework, and the fact someone says global is evil, how would you manage the settings?
Thanks
Edit1: Please don't tell to use constats, i have tons of settings and i don't want to make a tons of constant + they must be editable
There's nothing wrong with your configuration array. It's quite a common approach. The fallacy globals are evil is cargo cult programming advise. Please ignore.
Now the $config array is often easy to use by itself. But you can expand on that. It's quite simple for example to turn it into an ArrayObject once initialized:
$config = new ArrayObject($config, 2);
This will allow you to access the settings as $config["setting"] and $config->setting alike. It's easier on the eyes.
If you also want to avoid having to import the array everywhere, because you sometimes need just a single value, then expand with a wrapper function config("setting") for convenience.
Btw, I'm usually using a mix of config array and constants myself. And I made a little management tool for plugins and a settings array in a central config.php. http://web135.srv3.sysproserver.de/milki.erphesfurt.de./genericplugins/genconfig.html
If your settings are constant and do not change then consider using define() - http://php.net/manual/en/function.define.php
//Set anywhere like this
define("DB_NAME", "stackoverflow");
// You can then read it from anywhere using
echo DB_NAME;
Is they need to be editable then you can use globals, but ensure that register_globals is off.
If you are using PHP5 then you could implement the Registry pattern to do this.
I'd be tempted to use a define rather than a variable, as this would at least remove the need for global variables.
That said, you can't (easily) store complex data types such as arrays via defines, so you'll want to factor this in.
Pass the global as a parameter of function
manageCache($config);
Globals are really evil
Normally you would have a config folder somewhere in your framework that you auto include on startup.
It would potentially look like this:
ROOT/
config/
db.php
cache.php
constants.php
You would then have something like a Config class that handles importing this configuration variables and converting them into instance variables. This way you can access these configuration variables like this:
$config->get_config('settings_1');
Related
I'm trying to improve my website engine. So I can stop setting global $vars inside functions
So now I'm setting all my global site vars with this instead:
define('ROOT_prefix', 'mysitename_');
define('ROOT_support', 'support#mysite.com');
I can access them anywhere. But it does not feel as good (or smart) practice..
I know very little about classes.. but couldn't/should't I use a class for this instead?
This works:
class ROOT {
public static $prefix = 'mysitename_';
public static $support = 'support#mysite.com';
}
And then anywhere on my site I can use this (even inside functions):
echo '<h1>Please contact support at: '.ROOT::$support.' </h1>';
Is this a good way, or is there a better way?
If the value of these "globals" will not be changed for the entire run-time of the script, then you absolutely should use constants, as this is exactly what they are for.
You should keep them all centralized in a common include file for readability.
(Edit based on comments follows)
Since it looks like you're using constants for some kind of localization of content, it might be prudent to use a class for this. As I have said: using constants for non-changing values in a procedurally oriented script isn't bad practice in itself, but in the context of localization, there are better ways.
One such would be to create a class with some static methods to translate a string based on the passed ini file, this would be in line with the dependency injection mentioned in other comments and answers here.
An example of such a class would look something like this:
class Localizer {
public static function localize($langFile, $string) {
if (!file_exists($langFile)) {
throw new Exception($langFile . 'not found!');
}
$lang = parse_ini_file($langFile);
return (!empty($lang[$string])) ? $lang[$string] : false;
}
}
You can use it like this:
echo Localizer::localize('./english.ini', 'hello') . "\n";
echo Localizer::localize('./english.ini', 'email') . "\n";
This assumes an ini file that looks like this:
; english.ini
hello = 'Hello!'
email = 'test#test.com'
Realistically, this is probably a more "proper" way than declating a boat load of constants for each language your application runs in, but it is going to open the file every time you need to localize a string, which wouldn't be optimal for a very high volume application on a large system. But, as with a constant, you will be able to access the static methods of a class in the scope of any function in your application so long as the class was included beforehand. No need to use constants or declare globals.
The most proper and efficent way to do it would be to instantiate a class instead of using static methods, which would load the files into memory once and keep them there, eliminating the need to open the file for every string translated. But this would require that you are able to pass the variable containing the instantiation of this class to every function in your code that requires it, or declare it as global, which was exactly what you were trying to avoid in the first place.
So in order to do this, you would probably need to re-structure your code to allow for dependency injection throughout.
To continue with your current code and structure, you can continue using generated constants, which will be much messier, less "proper", and not expandable, but the advantage is that you will only read the ini files once, and keep them in memory.
Or you can use a static method, which is more "proper" but needs to read a file every time you localize a string, meaning that on large systems, it could cause some inefficiency. Realistically though, if your application in low volume, you will likely never see problems arise from this.
The main advantages of this method are expandability, and clean code. While declaring constants might be more efficient in terms of file opening and memory usage in the very short term, in most cases, it's not as expandable, because you can have an unlimited number of strings and language files, which means you could end up in a situation in the future where your loading thousands and thousands of constants every time your application loads.
If you use a class, and only load the files/strings that are needed by that specific user at run time, you can avoid this, no matter how many languages and strings you support.
Static class variables aren't any better than constants. They're still globally accessible values. There's no real change.
If you want to be improving your style, you should be using dependency injection. This simply means that you pass all variables that a function or class needs into the function/class as parameters. It's that simple, really. If you want to decouple your code, you need to create borders between different pieces. That means one piece does not "reach out" and get a global variable; instead you define that piece as accepting a parameter and write another piece that passes it that parameter.
Please read How Not To Kill Your Testability Using Statics for an in-depth explanation of this topic.
You may set variable to global when you need it. Just use global ${$variablename};.
where $variablename contain name of needs variable. For example it may be array keys or values.
Declaring your properties as public allows for their modification.
If you want them to be constants, as they were when created with define, you'll have to declare them as protected and use methods to access them :
class ROOT {
protected $prefix = 'mysitename_';
protected $support = 'support#mysite.com';
public static getPrefix(){
return $this->prefix;
}
public static getSupport(){
return $this->getSupport;
}
}
This way is actually quite better than using define() actually.
It's a step forward to singleton patterns (http://en.wikipedia.org/wiki/Singleton_pattern).
Next step is the building of an Application class (ROOT name sounds fine) which would contain these constants, and perhaps load them from a configuration file.
In this Application singleton, you can build some main function, like an init() for a bootstrap, inclusion of other classes, database configuration, logging system, templating system, and so on...
Is there anyway in php, by which we can define our own magic constants, which value could vary throughout the program and how to define variables with the SUPER GLOBAL SCOPE.
Just add the variable as an Apache environment variable:
SetEnv foo bar
You could set that in httpd.conf, apache2.conf, or .htaccess.PHP should then be able to access it via one or more of the following methods:
$_SERVER['foo']
$_ENV['foo']
getenv('foo')
While you can declare global variables, superglobals are limited to those found in PHP. You might want to keep your data as $_SESSION['mysuperglobal'], althou I suggest more elaborated patterns like a config-singleton, a registry or dependency injection.
You cannot define magic constant w/o building own flavour of PHP. But you can mimic this by putting all your "magic" define()s in separate file and including it in each of your script you can use auto_prepend_file config directive. Still, if you think you need something like this, the I'd try to rethink that approach. Whenever "magic" or "global" things comes to play, it's rather indication of need of refactoring.
I have custom config items in application/config/config.php.
Samples of my custom config items:
$config['website_title'] = 'ABC Website'; //Assume website title is fixed
.
.
.
etc
Now i can call $this->config->item('website_title') any where in my application. However, i don't find it efficient enough because i might have multiple $this->config->item('website_title') within the project. I came up with the following solution:
1.Create a function, within a helper, that return the config item as the following:
public function website_title() {
return $this->config->item('website_title');
}
2.Now i can call website_title() as many as i want.
Is this a good solution? Do you see any downsides?
Note: I try to avoid using global variables because i tried it and i
faced many unnecessary problems such as undefined variables,
surprised!
What do you mean by "efficient"? Runtime efficiency? Coding efficiency? Clarity?
In terms of runtime efficiency Truth's suggestion of using is perhaps the simplest and best. However, I prefer to code using a strict class/object implementation, and in reality defines are just global constants.
If you profile the vast majority of scripts, you will find that however you code your configuration referencing makes an immaterial impact on runtime, so I would suggest going for simplicity and clarity of coding every time.
One approach is to use a singleton class (there are lots of tutorials on doing this) and use the magic method __get() to allow you to dynamically overload parameter access. This is one case where I feel that you have to use a single class as these property methods only work with object (non-static) parameter references. Hence you can simply use:
$cfg = Configuration::get();
...
... $cfg->someConfigParam ... // to refer to a config parameter
...
... /* or even */ ... Configuration::get()->someOtherParameter ...
Note that $cfg in the above example essentially stores an object handle, so there is no material runtime cost in doing this, and you can put this statement at the top of each function or class constructor that references a config item if you don't want to litter your code with Configuration::get()->someOtherParameter type calls.
The Configuration::__get() access function , plus the class constructor can handle all the complexities of caching and access of the individual parameters. This also means that you con also encapsulate the source of the configuration: some application-specific D/B config table; one or more config files, ...; even cookies or URI parameters (so long as you include appropriate validation).
I personally don't recommend over loading with the __set() magic method as, IMO, overriding or setting a config parameter should be an explicit action, e.g. $cfg->setConfigItem( 'someValue', TRUE );
Here is a link to the documentation on my config class if you want some ideas.
I asked this sort of question on programmers once. I got a very good answer, simply use constants.
I.e. WEBSITE_TITLE
I'm not really sure what the best way to use global configuration options.
For example, if when a file is uploaded I want to move it in the correct folder.
I can hardcode the path, but it's not really the best thing.
I can use a CONSTANT
I can use config.ini and sets some common config options. Maybe then register a config object in Registry
How do you do? Any advice?
A Zend_Config object in the Registry is the usual method that ZF follows here. Many of the ZF classes can accept Configs, and there's pretty much no better way to deal with it within ZF.
(Just remember, the Registry pattern is little more than a glorified global anyway.)
Create a config.ini, and within it separate your configurations like so:
[development]
;File Upload settings
FileUpload.path = /some/path
[production]
;File Upload settings
FileUpload.path = /production/path
Now somewhere in your Bootstrap.php, you can do this:
$config = new Zend_Config_Ini(
self::$root . '/config/config.ini',
'development'
);
self::$registry->configuration = $config;
And in any controller:
$config = Zend_Registry::get('configuration');
echo $config->FileUpload->path;
I use Zend_Registry::set('foo', '/path/to/correct/folder') once, and then call it whenever I need it with Zend_Registry::get('foo') anytime I need it. Works great!
i have an application done in php and all configuration variables are loaded in a big $conf variable at the beginning of the script.
What is the better way to communicate this configuration variable to all other functions ?
make it a parameter of every function ? or use it with "global $conf;" statement in every function ?
is there a better way to do ?
Thanks
Use PHP constants.
For ponies sake, avoid using global variables at all costs :)
EDIT
Some explanations about "avoiding global variables at all costs" and possible alternatives:
https://stackoverflow.com/questions/357187/when-are-global-variables-acceptable/357361#357361
http://my.opera.com/zomg/blog/2007/08/30/globals-are-evil
https://stackoverflow.com/questions/1285700/what-are-some-good-tips-for-a-new-php-developer (especially section Scope of the accepted answer)
Make a configuration class that stores the options. Make it a singleton PHP Manual describes that here. This is just an alternative to global variables. It would allow you to define a method to load options from a file or a php array and store them in the class. Other classes can use the configuration object by getting the single instance and accessing the data.
I think this is better than a global variable as the other answer also says. But it still lets you define options as arrays, or even nested arrays if you want (and set up your class accordingly)
Your use of a single global-scoped variable $conf is perfectly fine. Many PHP applications do that. But there are drawbacks to combat.
In particular it's often more effort to write global $conf in each function where you want to access them. In that case I would recommend a simple global wrapper function instead:
function conf($key, $sub="") {
global $conf;
if (defined($key))
{ return constant($key); }
elseif ($sub)
{ return $conf[$key][$sub]; }
else
{ return $conf[$key]; }
}
This allows you to write conf("setting1") or conf("main", "opt3") whereever you need it. Still you can access the global $conf where that is more suitable. As extra bonus you can make this wrapper function more intelligent, by allowing it to query alternative settings etc. Also see how easy it is to also sneak in conf("CONSTANT") support.
Keeping this adds some flexibility in defining your configuration settings. Personally I use a similar approach, albeit with defining the array step-wise rather than at once:
$app_config["title"] = ...;
$app_config["editor.btns"] = ...;
define("RESTRICTED_MODE", true);
I'm preferring the array() approach, but transitioning to an ini-file for storage at a later point is not a problem. Also you can still make your config array read-only if the need arises. For that just define an:
class Read_Only_Array extends ArrayObject { function offsetSet() {} }
$conf = new ReadOnlyArray($conf);
So it's still accessible as array, but you easily established what others use cumbersome registries or syntactic workarounds for.
The "globals are evil" meme is completely baloney. It's parrotted on SO by cargo cult programmers with a desire for oversimplification and newcomers who glance over bold headlines without understanding the language semantics.
In your case, you just use a single $conf variable, and do not pollute the shared scope. When it is coherently accessed from the whole application, then it's not an issue. You should however strictly avoid to modify contents at runtime (use Read_Only_Array if need be). Create a secondary $app_var[] aray for that, and keep your config settings static.