Использовать в PHP 7.2 функцию each не рекомендуется. В документации говорится:
Предупреждение: Эта функция УСТАРЕЛА, начиная с PHP 7.2.0. Полагаться на эту функцию крайне не рекомендуется.
Как я могу обновить свой код, чтобы не использовать ее? Вот некоторые примеры:
$ar = $o->me;
reset($ar);
list($typ, $val) = each($ar);
$out = array('me' => array(), 'mytype' => 2, '_php_class' => null);
$expected = each($out);
for(reset($broken);$kv = each($broken);) {...}
list(, $this->result) = each($this->cache_data);
// итерация до конца массива или до предела > длины массива
$i = 0;
reset($array);
while( (list($id, $item) = each($array)) || $i < 30 ) {
// некоторый код
$i++;
}
Когда я выполняю этот код на PHP 7.2, я получаю следующую ошибку:
Устарело: функция each() устарела. Это сообщение будет подавлено при дальнейших вызовах.
Ответ 1
Для первых двух примеров вы можете использовать функции key() и current() для присвоения нужных вам значений.
$ar = $o->me; // сброс не нужен, так как вы только что создали массив
$typ = key($ar);
$val = current($ar);
$out = array('me' => array(), 'mytype' => 2, '_php_class' => null);
$expected = [key($out), current($out)];
В этих случаях вы можете использовать next() для перемещения курсора, но это может быть необязательно, если остальная часть вашего кода не зависит от этого.
В третьем случае я бы предложил foreach() вместо того, чтобы использовать цикл и назначать $kv внутри цикла.
foreach ($broken as $k => $v) {
$kv = [$k, $v];
}
В четвертом случае – похоже, что ключ не учитывается в list(), поэтому вы можете присвоить текущее значение.
$this->result = current($this->cache_data);
Как и в первых двух случаях, может потребоваться переместить курсор в next() в зависимости от того, как остальная часть вашего кода взаимодействует с $this->cache_data.
Пятый пример можно заменить на цикл for().
reset($array);
for ($i = 0; $i < 30; $i++) {
$id = key($array);
$item = current($array);
// некоторый код
next($array);
}
Ответ 2
На самом деле существует множество случаев, когда each() может быть заменен, вот почему существует огромное количество вариантов.
-while (list($key, $callback) = each($callbacks)) {
+foreach ($callbacks as $key => $callback) {
// ...
}
Или:
-while (list($key) = each($callbacks)) {
+foreach (array_keys($callbacks) as $key) {
// ...
}
Я сделал инструмент под названием Rector, который преобразует код так, как описано выше (+ есть еще больше случаев).
4 шага по обновлению кода
1. Установка пакета
composer require rector/rector --dev
2. Создайте конфиг rector.php.
vendor/bin/rector init
3. Добавьте набор PHP_72
<?php
use Rector\Core\Configuration\Option;
use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters->set(Option::SETS, [
Setlist::PHP_72,
]);
};
4. Запустите его в своем коде.
vendor/bin/rector process src --set php72
Надеюсь, это поможет вам.
Ответ 3
Я нашел способ исправить это и решил поделиться информацией. Здесь также приведены другие примеры того, как модернизировать циклы each() в foreach().
Случай 1: Отсутствует $value
reset($array);
while (list($key, ) = each($array)) {
Обновляется до:
foreach(array_keys($array) as $key) {
Случай 2: Отсутствует $key
reset($array);
while (list(, $value) = each($array)) {
Обновляется до:
foreach($array as $value) {
Случай 3: Ничего не пропущено
reset($array);
while (list($key, $value) = each($array)) {
Обновляется до:
foreach($array as $key => $value) {
Ответ 4
Вы можете создать свою собственную функцию each(), используя key(), current() и next(). Затем замените свои вызовы этой функцией, например, так:
<?php
function myEach(&$arr) {
$key = key($arr);
$result = ($key === null) ? false : [$key, current($arr), 'key' => $key, 'value' => current($arr)];
next($arr);
return $result;
}
Применение:
1.
$ar = $o->me;
reset($ar);
list($typ, $val) = myEach($ar);
2.
$out = array('me' => array(), 'mytype' => 2, '_php_class' => null);
$expected = myEach($out);
3.
for(reset($broken);$kv = myEach($broken);) {...}
Ответ 5
Вот несколько способов сделать это:
Стандартный цикл foreach:
foreach($this->contents as list($products_id)) {
$total_items += $this->get_quantity($products_id);
}
Или:
$total_items = array_reduce($this->contents, function($acc, $item) {
return $acc + $this->get_quantity($products_id[0]);
});
Или в функциональном исполнении:
$total_items = array_sum(array_map([$this, 'get_quantity'],
array_column($this->contents, 0)));
Ни одному из этих методов не нужен reset($this->contents);, предшествующий данным примерам.
Ответ 6
То, что вы точно не должны делать, это поместить функцию «обратно в php», добавив ее в параметр auto_prepend_file в php.ini:
auto_prepend_file = "/var/www/php/auto_prepend.php"
Затем создайте файл и введите в него функцию с оберткой function_exists.
<?php
/**
* Добавляет устаревшую функцию each() обратно в 7.2
*/
if (!function_exists('each')) {
function each($arr) {
$key = key($arr);
$result = ($key === null) ? false : [$key, current($arr), 'key' => $key, 'value' => current($arr)];
next($arr);
return $result;
}
}
По сути, это объявляет функцию до запуска вашего php-приложения. Когда ваше приложение попытается запустить каждую функцию, вместо нее будет использована ваша версия.
Это абсолютно не тот способ, с помощью которого вы должны подходить к этой проблеме, особенно в производственном коде! Однако, если вы разработчик с ограничениями по времени и просто хотите попробовать произвольные фреймворки для своего следующего проекта, а они не были обновлены для работы на вашем локальном сервере разработки без отката до вашей версии php, и если вы приняли на себя обязательства по кодовой базе для вашего проекта, пожалуйста, идите вперед и внедряйте изменения в принятом ответе, потому что они действительно работают.
Web