Доступ к теме foreach

#php

#php

Вопрос:

Когда я перебираю массив массивов с foreach помощью, я могу напрямую перейти к следующему измерению, используя list() ключевое слово (или сокращенную [] нотацию), например:

 $array_num = [
    [1, 2, 3],
    [4, 5, 6],
];

foreach ($array_num as [$deep_value]) {
    echo $deep_value, ' ';
}
// prints: 1 4

$array_assoc = [
    ['foo' => 1, 'bar' => 2, 'baz' => 3],
    ['foo' => 4, 'bar' => 5, 'baz' => 6],
];

foreach ($array_assoc as ['baz' => $deep_value]) {
    echo $deep_value, ' ';
}
// prints: 3 6
 

Существует ли аналогичная концепция для массивов объектов?

 class Example {
    public $foo;
    public function __construct(int $number = 1) {
        $this->foo = $number;
    }
}

$array_obj = [
    new Example,
    new Example(4),
];
foreach ($array_obj as foo<-$object) { // obviously wrong
    echo $object, ' ';
}
 

Вариант использования точно такой же, как и в начальной функции (распаковка вложенных массивов в переменные). Одним из примеров может быть доступ к большому количеству свойств в объекте:

 foreach ($array_assoc as ['foo' => $foo, 'bar' => $bar, 'baz' => $baz]) {
    $speed = $baz / $foo / $bar;
    echo "The $foo horses ate $baz apples in the last $bar hours.n";
    echo "That's $speed apples per horse per hour!nn";
}
 

который масштабируется в порядке (2) x (сумма длин имен свойств).

против.

 foreach ($array_obj as $object) {
    $speed = $object->baz / $object->foo / $object->bar;
    echo "The {$object->$foo} horses ate {$object->$baz} apples in the last {$object->$bar} hours.n";
    echo "That's $speed apples per horse per hour!nn";
}
 

который масштабируется в порядке (длина имени переменной объекта) x (количество использований в цикле).

или

 foreach ($array_obj as $object) {
    [$foo, $bar, $baz] = [$object->foo, $object->bar, $object->baz];
    $speed = $baz / $foo / $bar;
    echo "The $foo horses ate $baz apples in the last $bar hours.n";
    echo "That's $speed apples per horse per hour!nn";
}
 

который масштабируется в порядке (длина имени переменной объекта) x (сумма длин имен свойств).

При небольших циклах или небольшом количестве свойств это не имеет большого значения. С увеличением длины имен переменных и использования в циклах последние два метода быстро становятся значительно более подробными и более трудными для чтения. Итог, я либо

  • дайте моему объекту безответственно короткое имя,
  • спамить мой цикл с $object-> помощью, или
  • извлеките все свойства объекта в начале цикла довольно подробным способом, что делает назначение объектной переменной устаревшим в первой строке цикла.

Ни то, ни другое не способствует удобочитаемому и поддерживаемому коду. Определение прямо в цикле, какие свойства я хочу, как это можно сделать с массивами, позволило бы мне использовать разумные имена переменных, пропускать ссылки на объекты во всем моем цикле и назначать только столько переменных, сколько мне действительно нужно. По сути, он превращает foreach операторы в эквиваленты операторов функций, которые вызываются несколько раз и сохраняют текущую область видимости.

Комментарии:

1. Я не уверен, какой результат вы ожидаете, и почему echo $object, ' '; недостаточно изменить into echo $object->foo, ' '; . Вы хотите получить «первое свойство» объектов из разных классов?

2. Это упрощенный пример, вариант использования точно такой же, как и в версии массива / списка. Например, если я извлекаю кучу свойств и нуждаюсь в них в своих собственных переменных, чтобы я мог их изменять или часто использовать, не обращаясь каждый раз к объекту, написание 10 строк $varX = $object->propertyX довольно громоздко и многословно. Я хотел бы иметь возможность просто распаковать их так же, как я мог бы, сначала преобразовав объект в массив.

Ответ №1:

Возможно, что отсутствует важная часть головоломки, но, поскольку вопрос стоит прямо сейчас, я не вижу причины, по которой этот фрагмент не будет делать то, что вы ожидаете:

 class Example {
    public $foo;
    public function __construct(int $number = 1) {
        $this->foo = $number;
    }
}

$array = [
    new Example,
    new Example(4),
];
foreach ($array as $object) {
    echo $object->foo, ' ';
}
// prints: 1 4 
 

Комментарии:

1. Вопрос не в поведении, этот фрагмент делает то, что я ожидаю, точно так же, как echo $subarray[0] или echo $subarray['baz'] сделал бы то же самое в моих первых 2 примерах. Разница между 2 соответствующими версиями заключается не в том, что они делают, а в том, насколько они подробны, что влияет на то, насколько хорошо / быстро они могут быть написаны, прочитаны, поняты и поддержаны. Представьте себе этот пример не только с одним echo для одного свойства, но и с 20 операциями над 7 свойствами. Добавление дополнительного object-> каждый раз быстро раздувает код. Я добавил подробное описание варианта использования к вопросу.