我遇到了一个奇怪的错误"在PHP中,因为我知道我是新手。
我正在开发一个TYPO3扩展,它对数据有一些重大的性能问题,或者我认为。 事实证明,第一次使用数组,它存储了我从数据库查询中获得的所有对象,正在逐渐取消。 之后的每次使用或循环都会很快。
代码如下所示:
$productsArr = $this->productRepository->findByDetail($category, $properties);
$newSortArr = array();
$familyProductList = array();
$counter = count($productsArr);
/** @var Product $product */
for($i = 0; $i < $counter; $i++) {
//it takes to long to do this
$product = $productsArr[$i];
if(!empty($productsArr[$i])) {
$newSortArr[$product->getInFamily()->getUid()][] = $product;
}
}
我首次使用对象数组的位置并不重要。首次使用阵列总是需要大约30秒。
有没有人遇到过类似的东西? 如果您需要更多信息,我很乐意提供。
提前致谢!
答案 0 :(得分:3)
您的$productsArr
不是数组,而是Exbase的类QueryResult
的对象,您可以使用foreach进行迭代或进行索引访问。此Object仅在需要时执行查询并构建其对象,因此,当您执行$product = $productsArr[$i];
时,Product
的所有$productsArr
- 对象都会构建。主要的问题是在PHP中构建对象的性能不佳并占用大量内存。
因此,为避免性能问题,请考虑使用
自定义查询$this->productRepository->createQuery()->statement('select * from ...')->execute();
获取您想要的内容,而不是加载大量对象,稍后在PHP中对其进行优化。
答案 1 :(得分:1)
正如杰伊已经提到的,你的结果不是数组,而是QueryResult
。仅供参考,可以通过在查询末尾添加->toArray()
将其转换为数组:
$productsArr = $this->productRepository->findByDetail($category, $properties)->toArray();
但这不会改善情况。有两个可能的问题:
迭代所有对象
QueryResult
的优势在于它仅反映查询的结果,但尚未解析所有对象。可以传递QueryResult,例如到分页小部件,然后只加载请求的结果(e.h.1-10,11-20等)。
由于您正在应用手动排序,因此会加载所有对象(取决于您的项目,这可能很多......)。
显然您想按家庭UID对产品进行分类?为什么不在ProductRepository
:
protected $defaultOrderings = array(
'inFamily.uid' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING
);
急切加载子对象
您的模型Product
可能与其他模型有关(e.h.产品到类别,产品到选项等)。默认情况下,Extbase会在访问对象时解析所有这些关系。
为了防止这种情况,您可以使用延迟加载来实现关系。这对于未在所有视图中使用的子对象都有意义。例如。在列表视图中,您只需要产品的标题,图片和价格,但您不需要该产品的所有选项。
要为这些子对象配置延迟加载,您只需在模型中添加@lazy
注释:
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\My\Extension\Domain\Model\ObjectStorageModel>
* @lazy
*/
protected $categories;
/**
* @var \My\Extension\Domain\Model\OtherModel
* @lazy
*/
protected $author;
延迟加载可能有一些缺点,例如:在某些情况下,当检查对象是OtherModel
的实例时,您会得到类型为LazyLoadingProxy
的对象。您可以解决大多数这些问题,或者在正常情况下甚至可能无法解决这些问题。如果你真的依赖于一个不是LazyLoadingProxy的对象的常见解决方法是这样的检查:
if ($product->getAuthor() instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
$product->getAuthor()->_loadRealInstance();
}
这确保无论如何你都拥有一个真实的&#34;对象的实例。
当您针对其中一个问题进行更改时,请不要忘记刷新系统缓存。
答案 2 :(得分:0)
我假设数组填充在第一行。您是否考虑过使用$product
填充foreach($productArr as $product)
而不是使用for
?