Я столкнулся с этим странным поведением с генераторами, которое не описано в руководстве по PHP.
У меня есть два цикла foreach — первый устанавливает некоторые значения по умолчанию, а второй перезаписывает их. Но так как некоторые пары ключ: значение отсутствуют, я не смог использовать array_merge (), поэтому я попытался использовать Generators для этой цели.
Я обнаружил, что ключи yield перезаписываются в ассоциативных массивах, даже если документы говорят:
Синтаксис для получения пары ключ / значение очень похож на тот, который используется для определения ассоциативного массива, как показано ниже.
Пример:
function yieldTest()
{
// those are array values (in my code - taken from data source; here static example)
$arr1 = ['a' => 1, 'b' => 2, 'c' => 3];
$arr2 = ['b' => 'B', 'd' => 'D'];
// 1st loop
foreach ($arr1 as $k => $v) {
yield $k => $v;
}
// 2nd loop
foreach ($arr2 as $k => $v) {
yield $k=>$v;
}
}
foreach(yieldTest() as $k=>$v) {
var_dump($k . ' = ' . $v) . "\n";
}
Это приводит к
string(5) "a = 1"string(5) "b = 2"string(5) "c = 3"string(5) "b = B"string(5) "d = D"
Так что ключи не были переопределены. Я ожидал получить следующий вывод:
string(5) "a = 1"string(5) "b = B"string(5) "c = 3"string(5) "d = D"
Это правильное поведение?
Генератор не является ассоциативным массивом. Это говорит «[Т] синтаксис для получения пары ключ / значение очень похоже на [..] ассоциативный массив «; это вовсе не говорит о том, что генератор ведет себя как ассоциативный массив.
На самом деле это не может ведут себя одинаково и дублируют ключи, так как ключи не известны всем сразу. Каждый ключ генерируется когда требуется, не раньше, чем. foreach
синтаксис зацикливания на генераторе на самом деле является синтаксическим сахаром для этого:
function foo() {
while (true) {
yield mt_rand(1, 2) => 'foo';
}
}
$foo = foo();
$foo->next();
echo $foo->key(), ' => ', $foo->current(), PHP_EOL;
$foo->next();
echo $foo->key(), ' => ', $foo->current(), PHP_EOL;
$foo->next();
echo $foo->key(), ' => ', $foo->current(), PHP_EOL;
$foo->next();
echo $foo->key(), ' => ', $foo->current(), PHP_EOL;
Это даст один и тот же ключ много раз, непредсказуемо. Должно быть очевидно, что он не ведет себя как массив вообще. Он просто возвращает пару значений, но они вообще не являются частью массива и, следовательно, не дедуплицируются. Кроме того, генератор выдает следующее значение только при запросе, в противном случае приведенное выше приведет к бесконечному циклу.
Других решений пока нет …