2012-06-29 1 views
1

У меня есть массив пользовательских входов ($ atts) в качестве ключей => пары значений. Некоторые из значений можно записать в виде формулы массива, например:PHP: Как превратить строку, содержащую выражение массива в реальном массиве?

'setting' => 'array(50,25)' 

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

$atts = array(
'setting' => array(50,25), 
'another' => 'not written as an array expression' 
) 

Автор логически, код будет:

Для каждого ключа => пары значений в массиве $ АТЦ ... если значение является строкой отформатированный как выражение массива ... взорвать это значение в массив.

Кто-нибудь знает, как я напишу это на PHP?

+1

Я не буду писать это в ответ, чтобы предотвратить бесконечные downvotes, но ... 'eval': http://php.net/manual/en/function.eval.php Кстати, не так лучше использовать JSON + 'json_encode/decode'? – biziclop

+0

@biziclop Кажется, что он работает только на PHP 5> = 5.2.0, но мое решение должно работать с PHP 4.3 или выше. Это для плагина WordPress. –

ответ

2

Используйте tokenizer:

function stringToArray($str) { 
    $array = array(); 
    $toks = token_get_all("<?php $str"); 

    if ($toks[1][0] != T_ARRAY || $toks[2] != '(' || end($toks) != ')') 
     return null; 

    for($i=3; $i<count($toks)-1; $i+=2) { 
     if (count($toks[$i]) != 3) 
      return null; 

     if ($toks[$i][0] == T_WHITESPACE) { 
      $i--; 
      continue; 
     } 

     if ($toks[$i][0] == T_VARIABLE || $toks[$i][0] == T_STRING) 
      return null; 

     $value = $toks[$i][1]; 
     if ($toks[$i][0] == T_CONSTANT_ENCAPSED_STRING) 
      $value = substr($value, 1, strlen($value) - 2); 

     $array[] = $value; 

     if ($toks[$i + 1] != ',' && $toks[$i + 1] != ')' && $toks[$i + 1][0] != T_WHITESPACE) 
      return null; 
    } 

    return $array; 
} 

выше будет работать только для литералов. Передача переменного, константы, выражение, вложенный массива или искаженная декларации массива будет возвращать null:

stringToArray('array(1,2)');    // works 
stringToArray('array(1,2.4)');   // works 
stringToArray('array("foo",2)');   // works 
stringToArray('array(\'hello\',2)');  // works 
stringToArray('array()');     // works 
stringToArray('array(1,2 + 3)');   // returns null 
stringToArray('array(1,2 + 3)');   // returns null 
stringToArray('array("foo"."bar")');  // returns null 
stringToArray('array(array("hello"))'); // returns null 
stringToArray('array($a,$b)');   // returns null 
stringToArray('array(new bar)');   // returns null 
stringToArray('array(SOME_CONST)');  // returns null 
stringToArray('hello');     // returns null 

Вы также можете использовать следующую команду для проверки, если ваша строка является выражение массива или нет:

function isArrayExpression($str) { 
    $toks = token_get_all("<?php $str"); 
    return (
     $toks[1][0] == T_ARRAY && 
     $toks[2] == '(' && 
     end($toks) == ')' 
    ); 
} 

isArrayExpression('array(1,2,3)');   // true 
isArrayExpression('array is cool');  // false 
isArrayExpression('array(!!!!');   // false 

Вы всегда можете настроить его под свои нужды. Надеюсь это поможет.

+0

Спасибо @netcoder! Я буду экспериментировать с этим, хотя мне нужно будет заставить его работать с вложенными массивами ... –

+0

@Shaun Scovil: Не должно быть так сложно. Проверьте, является ли токен «T_ARRAY», и если это так, вызовите рекурсивную функцию. – netcoder

+0

Это получилось великолепно, спасибо! Я все еще пытаюсь обдумать рекурсивные функции, но как только я это выясню, я отправлю свое полное решение для других ... –

0

Вы можете использовать eval, но я бы очень рекомендовал не использовать его, а вместо этого попытаться переосмыслить ваш дизайн на лучший способ обработки настроек. Так для примера, вместо того, чтобы хранить

'setting' => 'array(50,25)' 

Не могли бы вы сделать что-то вроде

'setting' => array('type'=>'array', 'value'=>'50, 25') 

затем при загрузке настроек вы можете сделать

switch($type) 
case 'array' 
    $val = explode(', ', $value) 

Или что-то подобное

Но, как и другие, я попытался бы сэкономить настройки с использованием сериализации

+0

Я полагаю, это требует немного большего объяснения. Я написал плагин WordPress, который позволяет администраторам веб-сайтов WP запускать встроенную WP-функцию WP_Query (http: //codex.wordpress.org/Class_Reference/WP_Query) из сообщения или страницы с использованием короткого кода. Таким образом, параметры короткого кода - это те же параметры, которые будут переданы WP_Query. Однако некоторые из этих параметров должны быть записаны как массивы. Я не хочу чрезмерно усложнять короткий код, поэтому я хотел бы просто дать пользователю написать [wpquery setting = "array (50,25)" another = "blah"]. Это имеет смысл? –

+0

ах ок. Извините, я ничего не знаю о WP, поэтому не могу дать предложения по лучшему пути. – Kris

+0

Ну, все, что вам действительно нужно знать, это то, что я пишу функцию, которая принимает параметры, а затем передает их другой функции. Они просто должны быть массивами изредка, а не строк. Это все еще просто PHP. –

0

Как было предложено в комментариях к сообщению, eval() будет делать то, что вы ищете. Однако на самом деле не всегда удобно хранить массивы в виде строк. Если вы хотите, чтобы сделать данные более портативными, я бы рекомендовал использовать json_encode() или даже serialize()

+0

Как я уже упоминал в Kris, я просто пишу функцию, которая принимает параметры, а затем передает эти параметры другой функции. Но некоторые из этих параметров должны быть массивами, поэтому первая функция принимает их как строки и затем должна преобразовывать их в массивы, прежде чем переходить ко второй функции. –

+0

Вы знаете, что вы можете передавать массивы как аргументы функции напрямую, не так ли? Из вашего описания это не похоже на то, что вам нужно создать строку массива. –

+0

Параметры моей функции ($ atts) задаются пользователем через Wordcress Shortcode API, поэтому формат, который они используют, похож на [wpquery setting = "array (50, 25)" another = "blah"] - который Затем я должен перевести на многомерный массив и перейти к функции WP_Query как массив ('setting' => array (50,25), 'another' => 'blah'). –

1
function stringToArray($string) { 
     $string = "return " . $string . ";"; 
     if (function_exists("token_get_all")) {//tokenizer extension may be disabled 
      $php = "<?php\n" . $string . "\n?>"; 
      $tokens = token_get_all($php); 
         foreach ($tokens as $token) { 
       $type = $token[0]; 
       if (is_long($type)) { 
        if (in_array($type, array(
          T_OPEN_TAG, 
          T_RETURN, 
          T_WHITESPACE, 
          T_ARRAY, 
          T_LNUMBER, 
          T_DNUMBER, 
          T_CONSTANT_ENCAPSED_STRING, 
          T_DOUBLE_ARROW, 
          T_CLOSE_TAG, 
          T_NEW, 
          T_DOUBLE_COLON 
          ))) { 
         continue; 
        } 


        exit("For your security, we stoped data parsing at '(" . token_name($type) . ") " . $token[1] . "'."); 
       } 
      } 
     } 

     return eval($string); 
    } 

$a='array(10,20)'; 
print_r(stringToArray($a));