无法解包带有字符串键的数组


Cannot unpack array with string keys

错误信息为:

FATAL ERROR未捕获错误:Cannot unpack array with string keys

我知道我可以简单地运行两次方法fetch()并传递['q']['bind'],但我正试图掌握使用新的...来解包值。我希望像这样传递这些值:

(string) SQL, (Array) Bind Values

但我认为它试图解包绑定值数组以及从fetch()方法的响应数组。有可能解包这个数组吗?

它看起来像这样:

array(2) {
    ["q"] => string(7) "example"
    ["bind"] => array(1) {
        ["example"] => string(3) "one"
    }
}

这是完整的代码,如果你需要看看它们是如何组合在一起的:

class ModelController {
    public static function execute($sql, $vals) {
        var_dump($vals);
    }
}
class ModelContainer {
    private $queries = [];
    public function add_model(Model $model, $name) {
        $this->queries[$name] = $model;
        return $this;
    }
    public function exec_all() {
        foreach($this->queries as $q) {
            ModelController::execute(...$q->fetch());
        }
    }
    public function exec($name) {
    }
}
class Model {
    private $sql;
    private $vals = [];

    public function set_q($statement) {
        $this->sql = $statement;
        return $this;
    }
    public function bind($vals = []) {
        $this->vals = $vals;
        return $this;
    }
    public function fetch() {
        return ['q' => (string)$this->sql,
            'bind' => $this->vals ];
    }
}
$m = new ModelContainer();
$m->add_model((new Model)->set_q('example SQL content here')->bind(['example' => 'example value here']), 'one');
$m->exec_all();

问题是splat操作符(数组解包操作符或...)不适用于关联数组。例子:

$array = [1, 2, 3];
$assoc = ["one" => 1, "two" => 2, "three" => 3];
var_dump(...$array); //Works
var_dump(...$assoc); //Doesn't work

你需要强制一个数组被数字索引,以便解包它。可以使用array_values:

$values = array_values($q->fetch());
ModelController::execute(...$values);

数组值将确保所有值都有一个顺序的数字键。

从PHP 8开始,将支持命名参数,这将使这两种情况都有效。只要数组键与参数名称匹配,就可以使用数组解包操作符和关联数组调用函数。在建议的RFC中有一个命名参数的例子,它说下面的代码应该在PHP 8中工作。

$params = ['start_index' => 0, 'num' => 100, 'value' => 50];
array_fill(...$params);

更新PHP 8.1

从PHP 8.1开始,解包数组也可以处理字符串键数组,因此错误FATAL error Uncaught error: Cannot unpack array with string keys将不再适用。

的例子:

$array1 = ["a" => 1];
$array2 = ["a" => 2];
$array = ["a" => 0, ...$array1, ...$array2];
var_dump($array); // ["a" => 2]
RFC:

如果您在尝试将关联数组解包到另一个数组时遇到此错误,则可以使用array_merge代替:

<?php
$inner = ["b" => "i", "c" => "i"];
$outer = ["a" => "o", "c" => "o"];
var_dump(array_merge($outer, $inner));
var_dump(array_merge($inner, $outer));

将产生

array(3) {
  ["a"]=>
  string(1) "o"
  ["c"]=>
  string(1) "i"
  ["b"]=>
  string(1) "i"
}
array(3) {
  ["b"]=>
  string(1) "i"
  ["c"]=>
  string(1) "o"
  ["a"]=>
  string(1) "o"
}