"Namespaces", constants and multiple PHP includes - php

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.

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!

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.

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);

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.

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.

Related

Zend 2 Imports and Global Namespace

I'm trying to wrap a legacy application in the Zend2 MVC framework. Thanks to the Zend Skeleton Application and code samples (especially https://github.com/maglnet/MaglLegacyApplication), I've solved most of my issues.
The one big issue I haven't been able to solve is illustrated by the following "legacy" file:
<?php
$test = "test";
function echo_test(){
global $test;
echo "test = ";
var_dump($test); # Makes NULL explicit
}
echo_test();
In the Controller for a ZF2 module, I capture the output of the include using an output buffer and stick that into the response object:
...
chdir($filePath) # Fixes relative includes
ob_start();
include $filePathAndName;
$output = ob_get_clean();
$response->setContent($output);
return $response;
... and I get back test = NULL.
I've seen warnings that ZF2 namespaces can create issues for legacy files and done my legwork to try and clarify why. According to the PHP guide, "Without any namespace definition, all class and function definitions are placed into the global space". Indeed, my sample is only slightly more complicated than the one listed below this statement... but it doesn't seem to work.
I also see that "You can set a variable after declaring a namespace, but variables will always exist in the global scope. They are never bound to namespaces.".
I continued to research and have finally discovered that this approach "will import the contents of the include file into the method scope, not the class scope".
Is there any way to process the file outside the method scope?
This is nothing to do with PHP namespaces. If you're including a file from within a ZF controller action, it will execute within that function's variable scope. For your example to work you'd need to declare global $test; in the ZF action as well before including the file (which would be horrible).
Without knowing exactly what your legacy code looks like it's hard to suggest a good solution. If there are a set number of globals you need to work, you can global them at some point earlier in the ZF application (with the goal of removing that hack at a later date). If you don't know in advance what the globals are, or if there are a large number of them, you may need to edit the legacy code to try and refactor out the reliance on globals.
Another option (at least theoretically) is to use exec(), shell_exec(), passthru() (automatically prints output), or curl (see shell_exec link, but only if you're hosting it outside ZF2 to avoid an infinite loop). This approach has its own list of drawbacks including:
Security (but see escapeshellarg)
Access to $_SERVER (the first comment on the question here may help), $_GET (but see this technique), $_POST, and especially $_COOKIES
A bug (may be resolved) in the php command line

PHP class for all site "globals" instead of define / global

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...

Php : what is better for configuration variable ? variable or parameter?

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.

Can you pass values to included files in PHP without using globals?

A pattern I tend to use often in PHP is setting a few globals (such as $page, $user, $db, etc), and then including a file which uses those globals. I've never liked the idea of using globals for this, though, so I'm looking for a better way.
The obvious solution is to define a class or function in the subfile, and call it after the file is included. There are cases where that can't work though, such as this:
// Add entries to a URI table from each section of the site
global $router;
$router = new VirtualFileSystem();
$sections = array('store', 'forum', 'blog');
foreach($sections as $section)
include dirname(__FILE__) . $section . '/routing.php';
// Example contents of 'forum/routing.php'
// implicitly receive $router from caller
$router->add('fourm/topic/', 'topic.php');
$router->add('forum/topic/new/', 'new_topic.php');
// etc
If I tried to wrap each routing.php in a function and call them each with $router as an argument, the same function name would clash after being defined in multiple files.
I'm out of ideas. Is there a better way to pass variables to included files without polluting the global namespace?
include and its siblings are basically just copy-paste helpers, and the code inside them shares scope with the calling block - as if you'd copy & paste it just where the include statement is. The sane way of using them is to think of them the same way you'd use #include in C or using in C# or import in Java: import some code to be referenced later on. If you have code in the included file that needs parameters, then wrap it in a function, put the parameters in the function arguments, use include_once at the top of the including file, and call the function with the parameters you want, wherever you need to. No globals required. As a rule of thumb, in regular operation, putting any code that "does" something (executes statements in the global scope) in an included file is best avoided IMO.
No, there is not. You're not passing variables to included files anyway. The code that is included behaves as if it was written where the include statement is written. As such, you're not passing variables into the included file, the code in the file can simply use the variables that are in scope wherever the include statement is located.
In your case the contents of forum/routing.php are not really standalone code, they're code snippets that depend on a very specifically set up scope to function correctly. That's bad. You should write your includable files in a way that does not couple them to the including code. For example, you could make your Router a static class and call it statically in forum/routing.php:
require_once 'virtual_file_system.class.php';
VirtualFileSystem::add('forum/topic/', 'topic.php');
As long as there is a class VirtualFileSystem in your app, this will work, and won't pollute the namespace any more than it already is anyway.
just isolate includes in a function:
function add_entries_to_router($router, $sections) {
foreach($sections as $section)
include dirname(__FILE__) . $section . '/routing.php';
}
$router = new VirtualFileSystem();
add_entries_to_router($router, array('store', 'forum', 'blog'));
You can try an OOP way by making a Configuration class as a singleton and retrieving it when you need it.
You could define magic methods for __get and __set to add them to an private array var and make the constructor private.
I usually define as constant only the path to my src project in order to load class files quickly and properly (and use some SPL too).
But I agree with #tdammers about the fact that an include keep the environment variables like if you were on the caller file (the one who makes the include).

Should I use CONSTANT's of method calls with a Registry pattern in PHP?

On my site I have a config file which has many settings that need to be accessed in many pages, including inside many class files. The config file is included into the header of every page build. Since I will be using a registry method to store some objects in, I am wondering if it would be better for me to store some setting in this class ass well since it will be available to all my other objects? From my experience over the last couple days, it seems accessing CONSTANTS inside of my class files is difficult sometimes. I am just not sure if it would be a good idea as it would need to call several methods to set and get the settings. Is it common practice to store settings in a registry type object? I have seen on some large projects that they have the methods in place to set/get settings but I have never really seen it in action.
I avoid constants in PHP, they make untestable. This is the gist of my preferred solution:
whatever.ini:
<?php
return array(
'setting-1' => 'value',
'setting-2' => 'another value',
);
config.php:
class config
{
public function __construct($path)
{
$this->cfg = include $path;
}
private $cfg;
public function get($key, $default)
{
return array_key_exists($this->cfg, $key)
? $this->cfg[$key]
: $default
;
}
}
index.php:
$cfg = new config('my.ini');
...
I like to keep things like this in a registry of some sort. Although for me this is because
the majority of my configuration
values are actually multiple parts
(ie arrays) so to map much of this
out using constants would get pretty
long winded. Additionally i dont
use php for my config files i always
use XML or YAML which is then parsed
any way so it jsut makes more sense
to go ahead and stick them in a
registry as opposed to using constant or globals.
It allows for a single api to get
these type of values whther its a db
connection object or the path to the
webroot on the filesystem
With that said i think it really depends on what the values are and how you intend to use them and if they are structure or essentially flat.
I use a combination of two approaches:
1: In every class/controller, I always start with a require_once('app_config.php') in which I have code like:
define('APP_SMTP_SERVER', 'mail.company.com');
that I can then reference as a constant.
2: I have a singleton "Registry" class where I can store keys and values. It has two exposed methods, getAttribute($key) and setAttribute($key, $value). When I save it to the database, I serialize the value, so it can store any data type you throw at it (single values or arrays, etc.).

Categories