tags:

views:

856

answers:

7

I have a function that includes a file based on the string that gets passed to it i.e. the action variable from the query string. I use this for filtering purposes etc so people can't include files they shouldn't be able to and if the file doesn't exist a default file is loaded instead. The problem is that when the function runs and includes the file scope, is lost because the include ran inside a function. This becomes a problem because I use a global configuration file, then I use specific configuration files for each module on the site. The way I'm doing it at the moment is defining the variables I want to be able to use as global and then adding them into the top of the filtering function.

Is there any easier way to do this, i.e. by preserving scope when a function call is made or is there such a thing as PHP macros?

Edit: Would it be better to use extract($_GLOBALS); inside my function call instead?

Edit 2: For anyone that cared. I realised I was over thinking the problem altogether and that instead of using a function I should just use an include, duh! That way I can keep my scope and have my cake too.

+3  A: 

Edit: Okay, I've re-read your question and I think I get what you're talking about now:
you want something like this to work:

// myInclude.php
$x = "abc";

// -----------------------
// myRegularFile.php

function doInclude() {
    include 'myInclude.php';
}
$x = "A default value";
doInclude();
echo $x;    // should be "abc", but actually prints "A default value"

If you are only changing a couple of variables, and you know ahead of time which variables are going to be defined in the include, declare them as global in the doInclude() function.

Alternatively, if each of your includes could define any number of variables, you could put them all into one array:

// myInclude.php
$includedVars['x'] = "abc";
$includedVars['y'] = "def";

// ------------------
// myRegularFile.php
function doInclude() {
    global $includedVars;
    include 'myInclude.php';
    // perhaps filter out any "unexpected" variables here if you want
}

doInclude();
extract($includedVars);
echo $x;        // "abc"
echo $y;        // "def"


original answer:

this sort of thing is known as "closures" and are being introduced in PHP 5.3

http://steike.com/code/php-closures/

Would it be better to use extract($_GLOBALS); inside my function call instead?

dear lord, no. if you want to access a global variable from inside a function, just use the global keyword. eg:

$x = "foo";
function wrong() {
    echo $x;
}
function right() {
    global $x;
    echo $x;
}

wrong();        // undefined variable $x
right();        // "foo"
nickf
A: 

When it comes to configuration options (especially file paths and such) I generally just define them with absolute paths using a define(). Something like:

define('MY_CONFIG_PATH', '/home/jschmoe/myfiles/config.inc.php');

That way they're always globally accessible regardless of scope changes and unless I migrate to a different file structure it's always able to find everything.

Bob Somers
I have most of the config variables set up in this fashion, but I have array of country codes, a database object etc that can't be defined in this manner.
Joshua
A: 

If I understand correctly, you have a code along the lines of:

function do_include($foo) {
  if (is_valid($foo))
    include $foo;
}

do_include(@$_GET['foo']);

One solution (which may or may not be simple, depending on the codebase) is to move the include out in the global scope:

if (is_valid(@$_GET['foo']))
  include $_GET['foo'];

Other workarounds exists (like you mentioned: declaring globals, working with the $_GLOBALS array directly, etc), but the advantage of this solution is that you don't have to remember such conventions in all the included files.

Cd-MaN
A: 

Why not return a value from your include and then set the value of the include call to a variable:

config.php

return array(
    'foo'=>'bar',
    'x'=>23,
    'y'=>12
);

script.php

$config = require('config.php');
var_dump($config);

No need to mess up the place with global variables

Ken
A: 

Is there any easier way to do this, i.e. by preserving scope when a function call is made

You could use:

function doInclude($file, $args = array()) {
  extract($args);
  include($file);
}

If you don't want to explicitly pass the variables, you could call doInclude with get_defined_vars as argument, eg.:

doInclude('test.template.php', get_defined_vars());

Personally I would prefer to pass an explicit array, rather than use this, but it would work.

troelskn
A: 

You can declare variables within the included file as global, ensuring they have global scope:

//inc.php
global $cfg;
$cfg['foo'] = bar;

//index.php
function get_cfg($cfgFile) {
    if (valid_cfg_file($cfgFile)) {
        include_once($cfgFile);
    }
}
...
get_cfg('inc.php');
echo "cfg[foo]: $cfg[foo]\n";
outis
A: 

I Have the same question, but in class methods. I have a method loadviewfile

class a {
     protected function loadViewFile($filename){
  if(is_file($filename)){
   ob_start();
   include($filename);
   $html =  ob_get_clean();
  }else{
   $html =  "error loading html";
  }
  return $html;
 }
}

and an other method in a class that extends the first

class b extends a {
    public function detail(){
        $test = "sfsdf";
        $this->loadViewFile("/Test/detail.php")
     }
}

i would like to use the $test variable in the detail.php file, but i can't use global, for every variable ! How does the include function does this?

steven Lots