【问题标题】:PHP: How to turn a string that contains an array expression in an actual array?PHP:如何在实际数组中转换包含数组表达式的字符串?
【发布时间】:2012-07-01 07:38:41
【问题描述】:

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

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

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

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

按逻辑编写,代码将是:

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

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

【问题讨论】:

  • 我不会将其写入答案以防止无限次投票,但是... eval: php.net/manual/en/function.eval.php BTW,使用 JSON + json_encode/decode 不是更好吗?跨度>
  • @biziclop 看起来它只适用于 PHP 5 >= 5.2.0,但我的解决方案需要适用于 PHP 4.3 或更高版本。这是一个 WordPress 插件。

标签: php arrays string multidimensional-array explode


【解决方案1】:

您可以使用 eval,但我强烈建议您不要使用它,而是尝试重新考虑您的设计以更好地处理设置。 因此,对于您的示例,而不是存储

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

你能做点什么

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

然后当你加载设置 你可以做

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

或类似的东西

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

【讨论】:

  • 我想这需要更多解释。我编写了一个 WordPress 插件,它允许 WP 网站管理员使用简码从帖子或页面运行内置的 WP 函数 WP_Query (codex.wordpress.org/Class_Reference/WP_Query)。因此,短代码参数与将传递给 WP_Query 的参数相同。但是,其中一些参数必须写为数组。我不想让简码过于复杂,所以我只想让用户编写 [wpquery setting="array(50,25)" another="blah"]。这有意义吗?
  • 啊好的。抱歉,我对 WP 一无所知,所以无法提供更好的建议。
  • 好吧,您真正需要知道的是,我正在编写一个接受参数的函数,然后将它们传递给另一个函数。它们只是偶尔需要是数组,而不是字符串。它仍然只是 PHP。
【解决方案2】:

正如您帖子的 cmets 中所建议的, eval() 将满足您的需求。但是,首先将数组存储为字符串并不实际。如果你想让数据更便携,我建议使用json_encode() 甚至serialize()

【讨论】:

  • 正如我对 Kris 提到的,我实际上只是在编写一个接受参数的函数,然后将这些参数传递给另一个函数。但是其中一些参数必须是数组,所以第一个函数将它们作为字符串接收,然后必须在传递给第二个函数之前将它们转换为数组。
  • 您知道可以直接将数组作为函数参数传递,对吧?根据您的描述,听起来您不必制作数组字符串。
  • 我的函数 ($atts) 的参数是由用户通过 WordPress Shortcode API 设置的,所以他们使用的格式类似于 [wpquery setting="array(50, 25)" another= "blah"] -- 然后我必须将其转换为多维数组并作为 array('setting'=>array(50,25),'another'=>'blah') 传递给 WP_Query 函数。
  • 我明白了。嗯,这很烦人。您可能需要扩展 netcoder 的答案。
【解决方案3】:

使用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

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

【讨论】:

  • 感谢@netcoder!我将对此进行试验,尽管我还需要让它与嵌套数组一起使用......
  • @Shaun Scovil:不应该那么难。检查令牌是否为T_ARRAY,如果是,则调用递归函数。
  • 效果很好,谢谢!我仍在尝试将注意力集中在递归函数上,但是一旦我弄清楚了,我将为其他人发布我的完整解决方案...
【解决方案4】:
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));

【讨论】:

  • 你的方式更好!支持数组的短语法!谢谢!
猜你喜欢
  • 2016-08-16
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-07
  • 2015-12-31
  • 1970-01-01
  • 2018-03-08
相关资源
最近更新 更多