如何更新使用已弃用 each() 函数的代码?

Posted

技术标签:

【中文标题】如何更新使用已弃用 each() 函数的代码?【英文标题】:How can I update code that uses the deprecated each() function? 【发布时间】:2018-03-11 13:59:35 【问题描述】:

php 7.2 中,each 已弃用。 The documentation 说:

警告 自 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);
    
    // 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() array_map() 也可以使用闭包。 这看起来像是来自 xmlrpc 库的东西。我也必须去修复一些东西,哈哈。 是的,它没有令人信服的理由而被弃用,只是让人们改变他们的代码,却一无所获。 PHP世界的另一个挫折。 wiki.php.net/rfc/deprecations_php_7_2 【参考方案1】:

2019+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 个步骤

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

希望它对您的迁移有所帮助。

如果有一些错误或异常,那就是 Rector 遗漏的情况。 Create an issue,所以我们可以修复它并使其适用于所有可能的情况。

【讨论】:

最后一个使用 key() 和 current() 的例子在值方面是正确的,但忽略了 each() 也将数组光标作为副作用前进的事实。此外,您可能指的是 list() 调用中的 $val 而不是 $callback 。一个合适的替换是: -list($key, $val) = each($callbacks); +$key = key($opt->option); +$val = current($opt->option); +next($callbacks); 您能为此创建一个问题以便解决吗? github.com/rectorphp/rector/issues 我没有使用那个库,我只是在谷歌上搜索 each() 替代品,在这里看到你的帖子,发现它很有用,但只是想我会指出那个小遗漏,这样你就可以更正您的帖子。 我明白了。在 Github 回购问题中仍然总是更好地解决这个问题。很少有维护人员访问他们的旧响应,并且该错误通常会影响更多人 @Nils 我已经更新了示例。很难从内联代码中读取文本注释,gist.github.com 会更好。你能查一下吗?【参考方案2】:

替换此代码

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];
                
            
        

【讨论】:

【参考方案3】:

    对于前两个示例,您可以使用key()current() 来分配您需要的值。

    $ar = $o->me;   // reset isn't necessary, since you just created the array
    $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-&gt;cache_data 交互。

    Fifth 可以替换为 for() 循环。

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

【讨论】:

对于 4.,我认为将 list($a, $b) = each($arr) 替换为 list($a, $b) = array(key($arr), current($arr)); next($arr); 不是吗? @Metal3d 是的,应该是等价的。虽然就个人而言,我不会使用列表,我只会使用 key() 和 current() 直接分配给 $a 和 $b。我知道这是多行代码,但它似乎比创建一个数组更直接,只是用 list() 取回值。不过,只是我的看法。 :-) 查看通用自动迁移版本如下:***.com/a/55514591/1348344 对于案例 1,我相信您需要确保在调用 current() 后内部指针是前进的,因为它不会移动指针。【参考方案4】:
 //  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);

【讨论】:

【参考方案5】:

扩展Petro Mäntylä案例3的优秀正确答案:

这是“案例 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);

【讨论】:

【参考方案6】:

使用这个功能怎么样?

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

【讨论】:

【参考方案7】:

你绝对不应该做的方式是将函数“重新放入 php”,方法是将其添加到 php.ini 中的 auto_prepend_file 设置中

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 应用程序运行之前声明函数。当您的应用程序尝试运行 each 函数时,它将使用您的版本。

这绝对是你应该解决这个问题的方式,尤其是在生产中!但是,您是一名有时间限制的开发人员,您只想为您的下一个项目尝试任意框架,并且它们尚未更新为在您的本地开发服务器上工作而无需回退您的 php 版本。

当您为项目提交代码库后,请继续执行已接受答案中的更改,因为它们确实有效。

我使用 Wee Zel 的每个函数的仿真

【讨论】:

在我的例子中,替换函数陷入了无限循环。可能是因为它没有考虑到reset()next()【参考方案8】:
reset($array);
while (list($key, $value) = each($array)) 

更新

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

【讨论】:

重要的是要注意这些是不等价的,尽管在大多数情况下一个 foreach 就足够了——如果你在 while 循环中修改 $array 它将遍历修改后的值。 foreach 创建列表的副本并对其进行迭代,因此对 $array 的突变不会改变循环。 @jpschroeder 好点,这是真的。此外,对于 foreach,不需要重置。 在foreach之前reset基本没用。 那是完全不同的函数...不能在递归中使用【参考方案9】:

我找到了修复它的方法,并想分享信息。这里还有其他关于如何将 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) 

【讨论】:

【参考方案10】:

以下是一些方法:

标准的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-&gt;contents);

【讨论】:

【参考方案11】:

您可以使用key()、current() 和next() 创建自己的each() 函数。然后用该函数替换您的调用,如下所示:

<?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);) ...

【讨论】:

如果你想完全模拟每一个,我猜你需要输出中的“key”和“value”键以及 0 和 1。 @Don'tPanic,已编辑答案,这种情况不需要它,但可能存在一些情况。谢谢建议

以上是关于如何更新使用已弃用 each() 函数的代码?的主要内容,如果未能解决你的问题,请参考以下文章

PHP 7.2:每个都已弃用。如何转换这些例子? [复制]

已弃用:each() 函数已弃用。 C:\xampp\htdocs\phprojekt\library\Zend\Cache\Backend.php 在第 66 行 [重复]

php 7.2 each() 函数已弃用[重复]

如何在不使用 each() 的情况下重写此函数? [复制]

已弃用:each() 函数已弃用。 C:\xampp\apps\magento\htdocs\vendor\colinmollenhour\cache-backend-file\File.php 第

更新 Swift 中已弃用的 Firebase 函数