Помогите загрузить константы, хранящиеся в сериализованном массиве, используя eval () и constant () - PullRequest
0 голосов
/ 05 января 2010

ОТКАЗ: Пожалуйста, прочтите внимательно, так как это НЕ вопрос хранения массивов в константах или простых методах eval () или serialize (). Это вопрос главным образом о том, как константы работают в PHP и почему функция constant () не работает для преобразования имени константы в значение константы. Спасибо.

ФОН: По разным причинам я начал с простого конфигурационного файла для доморощенного LAMP (PHP) CMS (в частной разработке). Оглядываясь назад, я мог ошибиться, и я перевел свое хранилище переменных в таблицу БД. Однако основная часть кода по-прежнему зависит от CONST, поэтому я использую eval ("define (A, B ...);") для загрузки значений DB и A в B в константы. Эта часть отлично работает. Но все становится немного сложнее.

ПРОБЛЕМА: У меня сейчас проблема с константами в массивах (NB. НЕ для массивов в константах). У меня есть большой массив GLOBAL, который называется defaults и содержит настройки конфигурации в формате, показанном ниже.

Сначала я заявляю: <?php define('THIS_IS_A_CONSTANT', 'abcdefg'); ?> (И ЭТО РАБОТАЕТ ...)

Далее я определяю $ GLOBALS ['defaults'] как следующий вложенный массив:

Array 
(
   'var_name' => Array 
        (
            'display' => THIS_IS_A_CONSTANT,
            'value'   => 12,
            'type'    => 'int',
            'params'  => Array ( ... )
        ),

    ...
    Lots more variables...
    ...

)

Чтобы клиент (который имеет доступ к файловой системе, но не имеет прямого доступа к БД, но может изменять определенные значения, включая большинство констант, через административный бэкэнд CMS) от взлома этой структуры массива, я сериализую структуру массива и сохраняю эту строку в БД. При каждом запросе страницы я сначала определяю все константы (хранящиеся в БД), используя eval (define (A, B ...)), а затем десериализирую приведенный выше массив (который был сериализован и сохранен в БД). Однако, что бы я ни пытался, я не могу получить значения в $GLOBALS['defaults']['var_name']['display'], которые будут распознаваться как значения , которые содержат константы. Вместо этого отображается имя константы, а НЕ значение константы (другими словами, мой вывод содержит THIS_IS_A_CONSTANT вместо 'abcdefg' ). Очень расстраивает, верно?

Я пробовал что-то вроде следующего (где $ arr содержит несериализованный массив, который я извлекаю из БД):

    foreach ($arr as $item => $contents) {
            $display = isset($contents['display']) ? $contents['display'] : 1;
            $value = constant("$display");

            // This doesn't work, though it seems like it should            
            $contents['display'] = $value;
            // Neither does this, no matter how much I juggle the quotation marks and backslashes
            eval("\$contents['display'] = constant(\"$value\");");
            // or this ...
            eval("\$contents['display'] = $value;");
            // or this ...
            eval("\$contents['display'] = \$value;");
            // or a number of other things...

    }
    $GLOBALS['defaults'] = $arr;

ВОПРОСЫ: Кто-нибудь имел дело с такой ситуацией раньше? Может кто-нибудь посоветовать мне, как заставить мои константы распознаваться как константы, а не строки. Нужно ли сериализовать мой массив по-другому? Или, может быть, обработать несериализованный массив иначе (после его извлечения из БД)? Это какая-то комбинация eval () и constant (), которая позволит мне это сделать? Почему константы в моем массиве ведут себя плохо, в то время как константы, которые я определяю, обычно работают без проблем? Буду очень признателен за любую помощь, так как я ломал голову над этим уже несколько дней и не нашел решений.

Всего наилучшего, Дакота.

Ответы [ 2 ]

0 голосов
/ 05 января 2010

Хотя у eval есть свои применения, это не один из таких случаев. Вы не представляете, что отправляется в eval во время выполнения, и по звукам вещей вы сохраняете что-то, что затем воспринимаете как код в месте хранения пользовательских данных.

Если константа была определена до объявления массива, то в сериализованной версии вместо метки будет содержаться значение. Я могу только предположить, что значение может отличаться в зависимости от контекста во время выполнения.

Я бы предположил, что лучшим решением было бы использование собственного макроязыка в PHP, например что-то вроде:

<?php
global $defs;

$defs=array(
  'THIS_IS_A_CONSTANT' => 'abcdefg',
  'SO_IS_THIS' => 23
);

// for inline constants  
foreach ($defs as $label =>$val) {
  define($label, $key);
}
replacer($defs,true);

function replacer($in, $init=false;)
{
   static $defs;
   static $vals;
   if ($init) {
      $defs=array_keys($in); 
      $vals=array_values($in);
      return count($in);
   }
   return str_replace($defs, $vals, $in);
  // you might want to use preg_replace() with a pattern based on $defs for a neater solution
}

function fix_var(&$in) 
{
   if (is_array($in)) {
      foreach ($in as $key=>$dummy) {
        fix_var($in[$key]);
      }
   } else {
      $in=replacer($in);
   }
}

?>

С * * +1010

0 голосов
/ 05 января 2010

Во-первых, почему ты оцениваешь? Из того, что вы говорите, вы хотите, чтобы значение $GLOBALS['defaults']['var_name']['display'] было значением константы THIS_IS_A_CONSTANT. Вы удалили сериализацию строки из своей базы данных и добавили ее в $GLOBALS['defaults'], и строка сохранила значение как имя константы, а не значение константы.

Вы пробовали:

<?php 
define('THIS_IS_A_CONSTANT', 'abcdefg');
$value = constant($GLOBALS['defaults']['var_name']['display']);
//$value should now be abcdefg not THIS_IS_A_CONSTANT
$GLOBALS['defaults']['var_name']['display'] = $value;
?>

Если "$ GLOBALS ['defaults'] ['var_name'] ['display']" содержит строку THIS_IS_A_CONSTANT, то все, что вам нужно сделать, это передать эту строку константе-функции.

Я что-то упустил?

...