这是一个简单的编程问题,源于我对PHP在foreach
循环期间处理数组复制和取消设置的方式缺乏了解。就像这样,我有一个阵列从我想要改变的外部源格式来找我。一个简单的例子是:
$myData = array('Key1' => array('value1', 'value2'));
但我想要的是:
$myData = array([0] => array('MyKey' => array('Key1' => array('value1', 'value2'))));
所以我采用第一个$myData
并将其格式化为第二个$myData
。我的格式化算法完全没问题。我的问题在于找到一种节省内存的方法,因为这些数组可能会有点笨拙。因此,在我的foreach
循环期间,我将当前数组值复制到新格式,然后我从原始数组中取消设置我正在使用的值。 E.g:
$formattedData = array();
foreach ($myData as $key => $val) {
// do some formatting here, copy to $reformattedVal
$formattedData[] = $reformattedVal;
unset($myData[$key]);
}
这里对unset()
的呼吁是个好主意吗?即,它是否节省了内存,因为我复制了数据而不再需要原始值?或者,PHP是否自动垃圾收集数据,因为我没有在任何后续代码中引用它?
代码运行正常,到目前为止,我的数据集的大小可以忽略不计,无法测试性能差异。我只是不知道自己是否会因为某些奇怪的错误或CPU点击而自行设置。
感谢您的任何见解 -sR
答案 0 :(得分:4)
使用foreach
运算符在&
循环中使用对变量的引用。这样就可以避免在内存中复制数组foreach
进行迭代。
编辑:正如Artefacto指出的那样,取消设置变量只会减少对原始变量的引用次数,因此保存的内存只是指针而不是变量的值。奇怪地使用引用实际上会增加总内存使用量,因为可能会将值复制到新的内存位置而不是被引用。
除非引用了数组, foreach在一份副本上运作 指定的数组而不是数组 本身。 foreach有一些副作用 在数组指针上。不要依赖 期间或之后的数组指针 foreach而不重置它。
使用memory_get_usage()
确定您正在使用的内存量。
对内存使用情况和分配here进行了很好的记录。
这是查看内存分配的有用测试代码 - 尝试取消注释注释行以查看不同方案中的总内存使用情况。
echo memory_get_usage() . PHP_EOL;
$test = $testCopy = array();
$i = 0;
while ($i++ < 100000) {
$test[] = $i;
}
echo memory_get_usage() . PHP_EOL;
foreach ($test as $k => $v) {
//foreach ($test as $k => &$v) {
$testCopy[$k] = $v;
//unset($test[$k]);
}
echo memory_get_usage() . PHP_EOL;
答案 1 :(得分:3)
请记住rules of Optimization Club:
规则#1和#2在这里特别相关。除非你知道你需要优化,除非你已经测量了优化的需要,否则不要这样做。添加未设置将增加运行时命中,并将使未来的程序员为什么要这样做。
不管它。
答案 2 :(得分:3)
在循环中处理文本(xml)文件的行时,内存不足。对于任何有类似情况的人来说,这对我有用:
while($data = array_pop($xml_data)){
//process $data
}
答案 3 :(得分:2)
如果在“格式化”中的任何时候你做了类似的事情:
$reformattedVal['a']['b'] = $myData[$key];
然后执行unset($myData[$key]);
与内存无关,因为您只减少了变量的引用计数,该变量现在存在于两个位置($myData[$key]
和$reformattedVal['a']['b']
内)。实际上,你保存了将变量索引到原始数组中的内存,但这几乎没有。
答案 4 :(得分:0)
除非您通过引用访问元素,否则unsetting将不会执行任何操作,因为您无法在迭代器中更改数组。
也就是说,修改你正在迭代的集合通常被认为是不好的做法 - 更好的方法是将源数组分解成更小的块(通过一次只加载一部分源数据)和处理这些,在你去的时候取消每个整个数组“块”。