У меня есть функция, которая включает файл на основе передаваемой ему строки, то есть переменной действия из строки запроса. Я использую это для целей фильтрации и т. д., Чтобы люди не могли включать файлы, которые у них не должно быть, и если файл не существует, вместо этого загружается файл по умолчанию. Проблема в том, что когда функция запускается и включает в себя область файла, теряется, потому что включение выполняется внутри функции. Это становится проблемой, потому что я использую глобальный файл конфигурации, а затем я использую определенные файлы конфигурации для каждого модуля на сайте. На данный момент я делаю это так: определяю переменные, которые я хочу использовать как глобальные, а затем добавляю их в начало функции фильтрации.
Есть ли более простой способ сделать это, то есть сохранить область видимости при вызове функции или есть такая вещь, как макросы PHP?
Редактировать: Было бы лучше использовать extract ($ _ GLOBALS); вместо этого внутри моего вызова функции?
Изменить 2: Для всех, кого это волновало. Я понял, что совсем не задумывался над проблемой и что вместо использования функции я должен просто использовать include, да! Так я смогу сохранить свой прицел и тоже съесть свой торт.






Редактировать: Хорошо, я перечитал ваш вопрос и, кажется, теперь понял, о чем вы говорите:
вы хотите, чтобы работало что-то вроде этого:
// 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"
Если вы изменяете только пару переменных и заранее знаете, какие переменные будут определены во включении, объявите их как 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/
Would it be better to use extract($_GLOBALS); inside my function call instead?
дорогой господин, нет. если вы хотите получить доступ к глобальной переменной изнутри функции, просто используйте ключевое слово global. например:
$x = "foo";
function wrong() {
echo $x;
}
function right() {
global $x;
echo $x;
}
wrong(); // undefined variable $x
right(); // "foo"
Это именно та проблема, с которой я столкнулся. Я пытаюсь разработать плагин для скрипта, но, к сожалению, этот скрипт делает некоторые странные вещи с глобальными переменными. Больно отслеживать все различные глобальные объекты, которые мне нужны, и объявлять их в функции «doInclude». Ну что ж ... Я думал, что $ GLOBALS подойдет, но это не работает из-за порядка функций и включает. Такова, наверное, жизнь разработчика плагина.
Когда дело доходит до параметров конфигурации (особенно путей к файлам и т. д.), Я обычно просто определяю их с помощью абсолютных путей с помощью define (). Что-то типа:
define('MY_CONFIG_PATH', '/home/jschmoe/myfiles/config.inc.php');
Таким образом, они всегда доступны глобально, независимо от изменений в области видимости, и если я не перейду на другую файловую структуру, он всегда сможет найти все.
У меня есть большинство переменных конфигурации, настроенных таким образом, но у меня есть массив кодов стран, объект базы данных и т. д., Которые не могут быть определены таким образом.
Если я правильно понимаю, у вас есть код примерно следующего содержания:
function do_include($foo) {
if (is_valid($foo))
include $foo;
}
do_include(@$_GET['foo']);
Одно из решений (которое может быть или не быть простым, в зависимости от кодовой базы) - переместить включение в глобальную область:
if (is_valid(@$_GET['foo']))
include $_GET['foo'];
Существуют и другие обходные пути (например, вы упомянули: объявление глобальных объектов, прямая работа с массивом $ _GLOBALS и т. д.), Но преимущество этого решения в том, что вам не нужно помнить такие соглашения во всех включенных файлах.
Почему бы не вернуть значение из вашего include, а затем установить значение вызова include для переменной:
config.php
return array(
'foo'=>'bar',
'x'=>23,
'y'=>12
);
script.php
$config = require('config.php');
var_dump($config);
Не надо путаться с глобальными переменными
Is there any easier way to do this, i.e. by preserving scope when a function call is made
Вы можете использовать:
function doInclude($file, $args = array()) {
extract($args);
include($file);
}
Если вы не хотите явно передавать переменные, вы можете вызвать doInclude с get_defined_vars в качестве аргумента, например:
doInclude('test.template.php', get_defined_vars());
Лично я бы предпочел передать явный массив, а не использовать его, но это сработает.
Это не ответ на вопрос, а скорее выражение «вы делаете это неправильно». Спасибо, Стив. Иногда бывают ситуации, когда бы было бы неплохо для запуска функции с использованием желаемой области видимости (т.е. глобальной). call_user_func_array_with_scope('function', $args, $this) был бы отличным, если бы он существовал ... (Или передавая "null" или global, чтобы передать ее в глобальную область. пригодится при создании плагина для работы с четко определенными ограничениями.
Вы можете объявить переменные во включенном файле как глобальные, убедившись, что они имеют глобальную область действия:
//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";
В моем случае обращение к вашему «Edit 2» и простое использование include не сработало, потому что у меня происходит намного больше вещей. По сути, думайте об этом как о классе "View", которому требуется viewscript.php, который, поскольку мы находимся в области действия плагина, я хочу передать "глобальную" область видимости скрипту просмотра без необходимости объявлять каждую переменную как глобальную в " doInclude "функция.