我有一个运行时间较长的PHP守护程序,该守护程序带有扩展ArrayIterator
的集合类。它包含一组自定义的Column
对象,通常少于1000个。通过xdebug
分析器运行它,我发现find
方法消耗了大约35%的周期。
如何以一种优化的方式在内部迭代这些项目?
class ColumnCollection extends \ArrayIterator
{
public function find($name)
{
$return = null;
$name = trim(strtolower($name));
$this->rewind();
while ($this->valid()) {
/** @var Column $column */
$column = $this->current();
if (strtolower($column->name) === $name) {
$return = $column;
break;
}
$this->next();
}
$this->rewind();
return $return;
}
}
最佳答案
您的find()
方法显然只返回带有查询的$name
的第一个Column对象。在这种情况下,按名称索引Array可能是有意义的,例如以对象的名称作为键存储对象。然后,您的查找将成为O(1)调用。ArrayIterator
实现ArrayAccess
。这意味着您可以像这样将新项目添加到您的收藏夹:
$collection = new ColumnCollection;
$collection[$someCollectionObject->name] = $someCollectionObject;
并通过方括号符号检索它们:
$someCollectionObject = $collection["foo"];
如果您不想更改客户端代码,只需在ColumnCollection中覆盖
offsetSet
即可:public function offsetSet($index, $newValue)
{
if ($index === null && $newValue instanceof Column) {
return parent::offsetSet($newValue->name, $newValue);
}
return parent::offsetSet($index, $newValue);
}
这样,执行
$collection[] = $column
将自动按名称添加$ column。有关演示,请参见http://codepad.org/egAchYpk。如果使用
append()
方法添加新元素,只需将其更改为:public function append($newValue)
{
parent::offsetSet($newValue->name, $newValue);
}
但是,
ArrayAccess
比本机数组访问慢,因此您可能需要将ColumnCollection更改为以下内容:class ColumnCollection implements IteratorAggregate
{
private $columns = []; // or SplObjectStorage
public function add(Column $column) {
$this->columns[$column->name] = $column;
}
public function find($name) {
return isset($this->data[$name]) ? $this->data[$name] : null;
}
public function getIterator()
{
return new ArrayIterator($this->data);
}
}
关于php - 如何优化PHP中的ArrayIterator实现?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42697550/