PHP:如何在实际数组中转换包含数组表达式的字符串?

时间:2012-06-29 18:53:58

标签: php arrays string multidimensional-array explode

我有一组用户输入($ atts)作为key =>值对。某些值可以写为数组表达式,例如:

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

在这些情况下,我想将该字符串中包含的数组表达式转换为实际数组。所以输出将是这样的:

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

逻辑上写,代码是:

对于数组$ atts中的每个key =>值对... 如果值是一个格式化为数组表达式的字符串... 将该值分解为数组。

有人知道我会用PHP写这个吗?

4 个答案:

答案 0 :(得分:3)

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));

答案 1 :(得分: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

您可以随时根据自己的需要进行调整。希望这会有所帮助。

答案 2 :(得分:0)

您可以使用eval,但我强烈建议您不要使用它,而是尝试重新考虑您的设计以更好的方式来处理设置。 所以对你的例子而不是存储

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

你可以做点什么吗

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

然后加载设置 你可以做到

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

或类似的东西

但与其他人建议的那样,我会尝试使用序列化来保存设置

答案 3 :(得分:0)

正如你的帖子评论中所建议的,eval()会做你想要的。但是,首先将数组存储为字符串并不实际。如果您希望数据更具便携性,我建议您使用json_encode()甚至serialize()