[这有点类似于问题:How to determine the first and last iteration in a foreach loop?,但是,已有10年历史的问题非常以array
为导向,并且没有一个答案与可以循环使用许多不同类型的事实兼容。
在PHP> = 7.4中给出了可以迭代的循环(数组,迭代器,生成器,PDOStatement
,DatePeriod
,对象属性等),我们如何在有效的方式,需要在循环之前/之后发生的代码,但仅在进入循环的情况下?
典型的用例是生成HTML列表:
<ul>
<li>...</li>
<li>...</li>
...
</ul>
<ul>
和</ul>
如果有某些元素,则必须打印。[[only。
empty()
:不能用于empty()
/ generators。each()
破坏了生成器的优势。each()
的其他建议)iterator_to_array()
的迭代,可以用作提供答案的起点:iterator_to_array()
这样的脚本应产生以下输出:
示例用法:
foreach
输出
<?php // Function that iterates on $iterable function iterateOverIt($iterable) { // How to generate the "<ul>"? foreach ($iterable as $item) { echo "<li>", $item instanceof DateTime ? $item->format("c") : ( isset($item["col"]) ? $item["col"] : $item ), "</li>\n"; } // How to generate the "</ul>"? } // Empty array iterateOverIt([]); iterateOverIt([1, 2, 3]); // Empty generator iterateOverIt((function () : Generator { return; yield; })()); iterateOverIt((function () : Generator { yield 4; yield 5; yield 6; })()); // Class with no public properties iterateOverIt(new stdClass()); iterateOverIt(new class { public $a = 7, $b = 8, $c = 9;}); $db = mysqli_connect("localhost", "test", "test", "test"); // Empty resultset iterateOverIt($db->query("SELECT 0 FROM DUAL WHERE false")); iterateOverIt($db->query("SELECT 10 AS col UNION SELECT 11 UNION SELECT 12")); // DatePeriod generating no dates iterateOverIt(new DatePeriod(new DateTime("2020-01-01 00:00:00"), new DateInterval("P1D"), new DateTime("2020-01-01 00:00:00"), DatePeriod::EXCLUDE_START_DATE)); iterateOverIt(new DatePeriod(new DateTime("2020-01-01 00:00:00"), new DateInterval("P1D"), 3, DatePeriod::EXCLUDE_START_DATE));
如果传递的迭代器不产生任何值,则不会得到任何输出。请参见
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> <ul> <li>4</li> <li>5</li> <li>6</li> </ul> <ul> <li>7</li> <li>8</li> <li>9</li> </ul> <ul> <li>10</li> <li>11</li> <li>12</li> </ul> <ul> <li>2020-01-02T00:00:00+00:00</li> <li>2020-01-03T00:00:00+00:00</li> <li>2020-01-04T00:00:00+00:00</li> </ul>
我绝不赞成将此作为一个好主意,这完全取决于您。我敢肯定,对于一些比较模糊的SPL类,有一些更优雅的方法可以做到这一点。通过扩展而不是合成来完成它可能也更简单。