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