如何更新使用已弃用 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->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->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() 函数的代码?的主要内容,如果未能解决你的问题,请参考以下文章
已弃用:each() 函数已弃用。 C:\xampp\htdocs\phprojekt\library\Zend\Cache\Backend.php 在第 66 行 [重复]
已弃用:each() 函数已弃用。 C:\xampp\apps\magento\htdocs\vendor\colinmollenhour\cache-backend-file\File.php 第