El mensaje de error es:

ERROR FATAL Error no detectado: no se puede desempaquetar la matriz con claves de cadena

Sé que simplemente puedo ejecutar el método fetch()dos veces y pasar el ['q']['bind'], pero estoy tratando de familiarizarme con el uso del nuevo ...para descomprimir valores. Quiero pasar los valores así:

1
(string) SQL, (Array) Bind Values

Pero creo que intenta desempaquetar la matriz de valores de vinculación, así como la matriz de respuesta del fetch()método. ¿Es posible desempaquetar esta matriz?

Se ve algo como esto:

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

Este es el código completo, en caso de que necesite ver cómo encaja todo:

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38
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();

El problema es que el operador splat (operador de desempaquetado de matriz o ...) no funciona con matrices asociativas. Ejemplo:

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

Debe forzar que una matriz se indexe numéricamente para poder desempaquetarla. Haces esto usando array_values ​​:

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

Los valores de matriz garantizarán que todos los valores tengan una clave numérica secuencial.

Actualizar

A partir de PHP 8 habrá soporte para argumentos con nombre que harán que ambos casos funcionen. Se documenta un ejemplo en el RFC propuesto para argumentos con nombre que dice que el siguiente código debería funcionar a partir de PHP 8

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

Actualizar PHP 8.1

Desde PHP 8.1, el desempaquetado de matrices también funciona con matrices de claves de cadena, por lo que el error ERROR FATAL Error no detectado: no se puede desempaquetar la matriz con claves de cadena ya no será aplicable.

Ejemplo:

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

RFC: PHP RFC: desempaquetado de matriz con claves de cadena

,

Si recibió este error cuando intentó desempaquetar una matriz asociativa en otra matriz, puede usar en su array_mergelugar:

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

Producirá

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16
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"
}