PHP Сохраняет область действия при вызове функции

#php

Вопрос:

У меня есть функция, которая включает файл, основанный на строке, которая передается в него, т. Е. переменная действия из строки запроса. Я использую это в целях фильтрации и т. Д., Чтобы люди не могли включать файлы, которые они не должны иметь возможности, и если файл не существует, вместо него загружается файл по умолчанию. Проблема заключается в том, что когда функция запускается и включает область действия файла, она теряется, потому что включение выполняется внутри функции. Это становится проблемой, потому что я использую файл глобальной конфигурации, а затем я использую определенные файлы конфигурации для каждого модуля на сайте. То, как я это делаю в данный момент, — это определение переменных, которые я хочу использовать в качестве глобальных, а затем добавление их в верхнюю часть функции фильтрации.

Есть ли более простой способ сделать это, т. Е. Сохранить область действия при вызове функции, или есть такая вещь, как макросы PHP?

Редактировать: Было бы лучше использовать extract($_GLOBALS); вместо этого внутри моего вызова функции?

Правка 2: Для всех, кому было не все равно. Я понял, что полностью обдумал проблему и что вместо использования функции я должен просто использовать include, да! Таким образом, я смогу сохранить свой прицел и тоже получить свой торт.

Комментарии:

1. В моем случае прибегнуть к вашему «Редактированию 2» и просто использовать включение не сработало, потому что у меня еще много чего происходит. По сути, думайте об этом как о классе «Представление», для которого требуется viewscript.php что, поскольку мы находимся в области плагина, я хочу передать «глобальную» область в viewscript без необходимости объявлять каждую переменную глобальной в функции «doInclude».

Ответ №1:

Редактировать: Хорошо, я перечитал ваш вопрос и, кажется, понял, о чем вы сейчас говорите:
вы хотите, чтобы что-то подобное работало:

 // 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"
 

Если вы изменяете только пару переменных и заранее знаете, какие переменные будут определены в include, объявите их как global в doInclude() функции.

В качестве альтернативы, если бы каждое из ваших включений могло определять любое количество переменных, вы могли бы поместить их все в один массив:

 // 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"
 

оригинальный ответ:

такого рода вещи известны как «закрытие» и внедряются в PHP 5.3

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

Было бы лучше использовать extract($_GLOBALS); вместо этого внутри моего вызова функции?

господи, нет. если вы хотите получить доступ к глобальной переменной изнутри функции, просто используйте global ключевое слово. например:

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

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

Комментарии:

1. Это именно та проблема, с которой я столкнулся. Я пытаюсь разработать плагин для скрипта, но, к сожалению, этот скрипт делает некоторые странные вещи с глобалами. Мне больно отслеживать все различные глобалы, которые мне нужны, и объявлять их в функции «doInclude». Ну что ж… Я думал, что $GLOBALS будет работать, но это не работает из-за порядка функций и включает в себя. Я думаю, такова жизнь разработчика плагинов.

Ответ №2:

Когда дело доходит до параметров конфигурации (особенно путей к файлам и тому подобного), Я обычно просто определяю их абсолютными путями, используя define(). Что-то вроде:

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

Таким образом, они всегда доступны во всем мире, независимо от изменений области, и если я не перейду на другую файловую структуру, она всегда сможет найти все.

Комментарии:

1. У меня есть большинство переменных конфигурации, настроенных таким образом, но у меня есть массив кодов стран, объект базы данных и т. Д., Которые Не могут быть определены таким образом.

Ответ №3:

Если я правильно понимаю, у вас есть код в соответствии с:

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

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

Одним из решений (которое может быть или не быть простым, в зависимости от кодовой базы) является перемещение включения в глобальную область:

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

Существуют и другие обходные пути (как вы уже упоминали: объявление глобалов, прямая работа с массивом $_GLOBALS и т. Д.), Но преимущество этого решения заключается в том, что вам не нужно запоминать такие соглашения во всех включенных файлах.

Ответ №4:

Почему бы не вернуть значение из вашего include, а затем установить значение вызова include в переменную:

config.php

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

script.php

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

Не нужно портить место глобальными переменными

Ответ №5:

Есть ли более простой способ сделать это, т. Е. сохранить область действия при вызове функции

Вы могли бы использовать:

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

Если вы не хотите явно передавать переменные, вы можете вызвать doInclude в get_defined_vars качестве аргумента, например.:

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

Лично я бы предпочел передать явный массив, а не использовать это, но это сработало бы.

Комментарии:

1. Это не ответ на вопрос, а скорее утверждение: «Вы делаете это неправильно». Спасибо, Стив. Иногда возникают ситуации, когда было бы неплохо запустить функцию, использующую желаемую область (т. Е. глобальную) call_user_func_array_with_scope('function', $args, $this) , было бы здорово, если бы она существовала… (Или передавая «null» или глобальный, чтобы передать его в глобальную область. Это пригодится при создании плагина для работы в рамках некоторых четко определенных ограничений.

Ответ №6:

Вы можете объявить переменные в включенном файле как глобальные, гарантируя, что они имеют глобальную область действия:

 //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";