无法使用字符串键解包数组

60

错误信息是:

FATAL ERROR Uncaught 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();

1
执行 $values = array_values($q->fetch()); ModelController::execute(...$values) - apokryfos
完全成功了!您能解释一下在这种情况下array_values()与解包有什么关系吗?感谢@apokryfos。 - Jaquarh
3个回答

99
问题在于使用扩展运算符(也称为数组展开运算符或...)时,无法与关联数组一起使用。例如:
$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);

17
这完全破坏了使用关联数组的原则,原本打算将键/索引用作SQL占位符匹配,也许这是我需要的限制?非常感谢你的解释!我会在能标记的时候进行标记。 - Jaquarh
2
我认为这是关于函数如何处理它们的参数列表的限制,例如func_get_args()始终是按数字索引。 - apokryfos
看来又要回到起点了,哈哈,不过还是很感谢这个知识! - Jaquarh
1
如果您希望以这种方式传递关联数组到函数中,请重写您的方法以接受一个数组:function execute(array $arguments) { var_dump($array['vals']); } - Jay Bienvenu
PHP 8.1 将支持命名参数,而在 PHP 8.0 中不可用。来源:https://www.amitmerchant.com/array-unpacking-with-string-keys-coming-in-php-81/ - Boschman
显示剩余4条评论

32

更新 PHP 8.1

自 PHP 8.1 开始,解包数组也适用于字符串键数组,因此错误 致命错误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: PHP RFC:使用字符串键进行数组展开


19

如果您在尝试将关联数组解包到另一个数组时遇到此错误,则可以使用 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"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接