Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как я могу обновить код, использующий устаревшую функцию each()?

Автор вопроса: yokogeriОтветов: 11

В PHP 7.2 each устарел. В документации говорится:

Внимание Эта функция устарела, начиная с PHP 7.2.0. Надеяться на эту функцию крайне не рекомендуется.

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

  1. $ar = $o->me;
    reset($ar);
    list($typ, $val) = each($ar);
    
  2. $out = array('me' => array(), 'mytype' => 2, '_php_class' => null);
    $expected = each($out);
    
  3. for(reset($broken);$kv = each($broken);) {...}
    
  4. list(, $this->result) = each($this->cache_data);
    
  5. // iterating to the end of an array or a limit > the length of the array
    $i = 0;
    reset($array);
    while( (list($id, $item) = each($array)) || $i < 30 ) {
        // code
        $i++;
    }
    

Когда я выполняю код на PHP 7.2, я получаю следующую ошибку:

Устарело: функция each() устарела. Это сообщение будет скрыто при дальнейших вызовах

  • выполнимо с foreach() 10.02.2018
  • array_map() с замыканием тоже подойдет. cchoe1 10.02.2018
  • Это похоже на материал из библиотеки xmlrpc. Что-то мне тоже нужно исправлять, лол. IncredibleHat 04.03.2020
  • Да, он устарел без веской причины и просто заставил людей изменить свой код и ничего не получить взамен. Еще одно разочарование в мире PHP. wiki.php.net/rfc/deprecations_php_7_2 PHPst 03.06.2020

phpeach

Ответы

Ответ 1 · рейтинг 80 · Don't Panic

  1. В первых двух примерах вы можете использовать key() и current() для присвоения нужных вам значений.

    $ar = $o->me;   // reset isn't necessary, since you just created the array
    $typ = key($ar);
    $val = current($ar);
    
  2. $out = array('me' => array(), 'mytype' => 2, '_php_class' => null);
    $expected = [key($out), current($out)];
    

    В этих случаях вы можете использовать next() для последующего перемещения курсора, но это может не понадобиться, если остальная часть вашего кода не зависит от этого.

  3. Для третьего случая я бы предложил вместо этого просто использовать цикл foreach() и назначить $kv внутри цикла.

    foreach ($broken as $k => $v) {
         $kv = [$k, $v];
    }
    
  4. В четвертом случае похоже, что ключ в list() не учитывается, поэтому можно присвоить текущее значение.

    $this->result = current($this->cache_data);
    

    Как и в первых двух случаях, может потребоваться переместить курсор с помощью next() в зависимости от того, как остальная часть вашего кода взаимодействует с $this->cache_data.

  5. Пятую можно заменить на for() петлю.

    reset($array);
    for ($i = 0; $i < 30; $i++) {
        $id = key($array);
        $item = current($array);
        // code
        next($array);
    }
    

Ответ 2 · рейтинг 45 · Tomas Votruba

2019+ Instant Upgrade of each()

Ознакомьтесь с демонстрацией каждой each миграции сильный>

На самом деле существует множество случаев, когда each() можно заменить, поэтому в этом вопросе так много разных ответов, за которые проголосовали.

-while (list($key, $callback) = each($callbacks)) {
+foreach ($callbacks as $key => $callback) {
     // ...
 }

А также:

-while (list($key) = each($callbacks)) {
+foreach (array_keys($callbacks) as $key) {
     // ...
 }

Вы можете заменить один за другим вручную. Но разве нет лучшего способа?

Помогаю мигрировать проекты, где таких кейсов более 150+. Мне лень, поэтому я сделал инструмент под названием Rector, который преобразует код так, как выше (+ есть еще случаи, но не хочу спамить ответ).

Это часть набора PHP_72.


4 Steps to Upgrade your Code

1. Install it

composer require rector/rector --dev

2. Create rector.php config

vendor/bin/rector init

3. Add PHP_72 set

<?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. Run it on your code

vendor/bin/rector process src --set php72

Я надеюсь, что это поможет вам с вашей миграцией.


Если есть какая-то ошибка или аномалия, это дело Ректора пропустил. Создайте задачу, чтобы мы могли исправить ее и заставить ее работать в каждом возможном случае.

Ответ 3 · рейтинг 38 · Petro Mäntylä

Я нашел способ исправить это и решил поделиться информацией. Вот также другие примеры того, как обновить циклы 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 · рейтинг 34 · Wee Zel

вы можете создать свою собственную функцию each(), используя key(), current() и следующий(). затем замените свои вызовы этой функцией, например:

<?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 · рейтинг 11 · Stewen Guyon

reset($array);
while (list($key, $value) = each($array)) {

ОБНОВИТЬ

reset($array);
foreach($array as $key => $value) {

Ответ 6 · рейтинг 5 · trincot

Вот несколько способов сделать это:

Стандартный цикл 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); перед ним.

Ответ 7 · рейтинг 3 · John Tilley

То, что вам определенно не следует делать, - это поместить функцию "обратно в php", добавив ее в настройку auto_prepend_file в php.ini.

auto_prepend_file = "/var/www/php/auto_prepend.php"

Затем создайте файл и введите функцию с оболочкой function_exists.

<?php
/**
 * Adds the depreciated each() function back into 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.

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

Я использовал эмуляцию каждой функции Wee Zel

Ответ 8 · рейтинг 1 · Martin

Чтобы расширить Petro Mäntylä отличный правильный ответ для Case 3 сильный>:

Вот полный пример ситуации "Случай 3", потому что я нахожу полные примеры гораздо более информативными, чем фрагменты однострочного кода:

Это подлинный код из сторонней базы старого кода (TCPDF)

УСТАРЕЛО

while (list($id, $name) = each($attr_array)) {
      $dom[$key]['attribute'][$name] = $attr_array[$id];
      ...
      ...
   }

Фиксированный

 // while (list($id, $name) = each($attr_array)) {
 foreach($attr_array as $feKey => $feRow){
    // $dom[$key]['attribute'][$name] = $attr_array[$id];
    $dom[$key]['attribute'][$feRow] = $attr_array[$feKey];
    ...
    ...
    }
 unset($feKey,$feRow);

Ответ 9 · рейтинг 1 · Sahil

Замените этот код

while (list($_key,$_resourceTypeNode) = each($GLOBALS['config']['ResourceType'])) {
//             if ($_resourceTypeNode['name'] === $resourceTypeName) {
//                 $this->_resourceTypeConfigCache[$resourceTypeName] = new CKFinder_Connector_Core_ResourceTypeConfig($_resourceTypeNode);

//                 return $this->_resourceTypeConfigCache[$resourceTypeName];
//             }
//         }

с этим

foreach ($GLOBALS['config']['ResourceType'] as $key => $_resourceTypeNode) {
            if (isset($_resourceTypeNode['name'])) {
                if ($_resourceTypeNode['name'] === $resourceTypeName) {
                    $this->_resourceTypeConfigCache[$resourceTypeName] = new CKFinder_Connector_Core_ResourceTypeConfig($_resourceTypeNode);

                    return $this->_resourceTypeConfigCache[$resourceTypeName];
                }
            }
        }

Ответ 10 · рейтинг -1 · Harendra Singh

 //  while (list($products_id, ) = each($this->contents)) {
   //  $total_items += $this->get_quantity($products_id);
 // }

Обновить до:

foreach(array_keys($this->contents) as $products_id) {
  $total_items += $this->get_quantity($products_id);
}

Другое условие:

foreach($this->contents as $key =>$value) {
  $total_items += $this->get_quantity($products_id);
}

Ответ 11 · рейтинг -2 · garsax

Как насчет использования этой функции?

function array_fetch(array $a) {
   $element = current($a);
   next($a);
   return $element;
}

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы