我如何在PHP中将字符串格式数组转换为数组类型

时间:2015-06-16 20:35:42

标签: php

我有一个像

这样的字符串格式数组
$string = "array(array('aaa','bbb','ccc','ddd'),array('AAA','BBB','CCC','DDD'))";

到数组,结果将是:

echo $array[0][0];
  aaa

3 个答案:

答案 0 :(得分:2)

如果您确定该字符串将始终包含数组(任何嵌套)和字符串,您可以编写自己的字符串解析器以避免eval字符串。

我很快将一个放在一起,应该处理递归数组,字符串和数字。它不处理布尔值,null和对象实例:

$string = "array(array('aaa','bbb','ccc','ddd'),array('AAA','BBB','CCC','DDD',1,2,3,-3.5)))";

class Tokens {
  private $tokens;
  public function __construct ($code) {
    $tokens = token_get_all("<?php " . $code . ";");
    $this->tokens = array_filter($tokens, function ($token) { 
      return (! is_array($token) || $token[0] !== T_WHITESPACE);
    });
    $this->pop();
  }
  public function pop () {
    return array_shift($this->tokens);
  }
  public function peek () {
    return $this->tokens[0];
  }
  public function doesMatch ($what) {
    $token = $this->peek();

    if (is_string($what) && ! is_array($token) && $token === $what) {
      return true;
    }
    else if (is_int($what) && is_array($token) && $token[0] === $what) {
      return true;
    }
    return false;
  }
  public function forceMatch ($what) {  
    $token = $this->peek();

    if (is_string($what) && (is_array($token) || $token !== $what)) {
      throw new Exception("unexpected token - expecting " . $what);
    }
    else if (is_int($what) && (! is_array($token) || $token[0] !== $what)) {
      throw new Exception("unexpected token - expecting " . token_name($what));
    }
    // consume
    $this->pop();
  }
}

function parseValue (Tokens $tokens) {
  if ($tokens->doesMatch(T_LNUMBER)) {
    // long number
    $token = $tokens->pop();
    return (int) $token[1];
  }
  if ($tokens->doesMatch(T_DNUMBER)) {
    $token = $tokens->pop();
    return (double) $token[1];
  }
  if ($tokens->doesMatch(T_CONSTANT_ENCAPSED_STRING)) {
    $token = $tokens->pop();
    return stripslashes(substr($token[1], 1, -1));
  }

  throw new Exception("unexpected value token");
}

function parseArray (Tokens $tokens) {
  $uminus = 1;
  $found = 0;
  $result = array();

  $tokens->forceMatch(T_ARRAY);
  $tokens->forceMatch("(");

  while (true) {
    if ($tokens->doesMatch(",") && $found > 0) {
      $tokens->forceMatch(",");
    }
    else if ($tokens->doesMatch(")")) {
      $tokens->forceMatch(")");
      break;
    }
    else if ($tokens->doesMatch("-")) {
      $tokens->forceMatch("-");
      $uminus = -1;
    }
    else if ($tokens->doesMatch(T_ARRAY)) {
      $result[] = parseArray($tokens);
    }
    else if ($tokens->doesMatch(T_LNUMBER)) {
      // long number
      $result[] = $uminus * parseValue($tokens);
      $uminus = 1;
    }
    else if ($tokens->doesMatch(T_DNUMBER)) {
      // double number
      $result[] = $uminus * parseValue($tokens);
      $uminus = 1;
    }
    else if ($tokens->doesMatch(T_CONSTANT_ENCAPSED_STRING)) {
      // string
      $string = parseValue($tokens);
      if ($tokens->doesMatch(T_DOUBLE_ARROW)) {
        $tokens->pop();
        $result[$string] = parseValue($tokens);
      }
      else {
        $result[] = $string;
      }
      $uminus = 1;
    }
    else {
      throw new Exception("yet unhandled token type");
    }

    ++$found;
  }
  return $result;
}

$tokens = new Tokens($string);
$result = parseArray($tokens);

var_dump("RESULT: ", $result);

我可以在http://gnuwin32.sourceforge.net/packages/gawk.htm中找到更高级的解析器版本。

我不是说我建议为此编写自己的解析器。编写自己的解析器可能很棘手且容易出错,如果有更简单的解决方案,应该避免使用它。我只想说清楚eval仍然可以避免。

首选解决方案可能仍然是与另一方达成一致,采用不同且广泛接受的格式(如JSON)。

答案 1 :(得分:1)

您的字符串未正确转义,请在外部使用",然后eval

$string = "array(array('aaa','bbb','ccc','ddd'),array('AAA','BBB','CCC','DDD'))";

$array = eval($string);

echo $array[0][0];

注意:eval与用户输入结合使用时很危险,并且由于安全问题而无法在所有环境中使用。

答案 2 :(得分:-1)

@cmorrissey你的回答很有帮助

这是解决方案:

    $string = '$array = array(array("aa","bb","cc","dd"),array("AA","BB","CC","DD"));';
    eval($string);
    echo $array[0][0];