我在大型 PHP 应用程序的特定部分遇到了一个相当奇怪的问题。有问题的应用程序部分从 MySQL 加载数据(主要是整数数据)并构建一个 JSON 字符串,该字符串将输出到浏览器。这些请求在 Chrome 的开发人员工具中以及通过curl
. 然而,我报告的 PHP 关闭处理程序在不到 1 秒的时间内执行了请求。
为了调试,我添加了一个调用fastcgi_finish_request()
,突然我的关闭处理程序报告了与 Chrome/curl 相同的时间。
通过一些调试,我将其缩小到一个特定的功能。我创建了以下简单的测试用例:
<?php
$start_time = DFStdLib::exec_time();
$product = new ApparelQuoteProduct(19);
$pmatrix = $product->productMatrix();
// This function call is the problem:
$ranges = $pmatrix->ranges();
$end_time = DFStdLib::exec_time();
$duration = $end_time - $start_time;
echo "Output generation duration was: $duration sec";
fastcgi_finish_request();
$fastcgi_finish_request_duration = DFStdLib::exec_time() - $end_time;
DFSkel::log(DFSkel::LOG_INFO,"Output generation duration was: $duration sec; fastcgi_finish_request Duration was: $fastcgi_finish_request_duration sec");
如果我调用$pmatrix->ranges()
(这是一个执行多次调用以mysql_query
获取数据并从该数据构建内存中 PHP 对象结构的函数),那么我会得到输出:
输出生成持续时间为:0.2563910484314 秒;fastcgi_finish_request 持续时间为:7.3854329586029 秒
在我的日志文件中。请注意,调用$pmatrix->ranges()
根本不会花费很长时间,但不知何故,它会导致 PHP FastCGI 处理程序花费 7 秒来处理请求。(即使我不打电话也是如此fastcgi_finish_request
——浏览器需要 7-8 秒来显示数据)
如果我注释掉对我的调用,$pmatrix->ranges()
我会得到:
输出生成持续时间为:0.0016419887542725 秒;fastcgi_finish_request 持续时间为:0.00035214424133301 秒
我可以发布该$pmatrix->ranges()
功能的整个源代码,但它很长。我想要一些关于从哪里开始寻找的建议。
甚至会导致这种行为的 PHP FastCGI 请求过程是什么?它是否调用析构函数/垃圾收集?它会关闭开放资源吗?我该如何进一步解决这个问题?
编辑:这是一个更大的源样本:
<?php
class ApparelQuote_ProductPricingMatrix_TestCase
{
protected $myProductId;
protected $myQuantityRanges;
private $myProduct;
protected $myColors;
protected $mySizes;
protected $myQuantityPricing;
public function __construct($product)
{
$this->myProductId = intval($product);
}
/**
* Return an array of all ranges for this matrix.
*
* @return array
*/
public function ranges()
{
$this->myLoadPricing();
return $this->myQuantityRanges;
}
protected function myLoadPricing($force=false)
{
if($force || !$this->myQuantityPricing)
{
$this->myColors = array();
$this->mySizes = array();
$priceRec_finder = new ApparelQuote_ProductPricingRecord();
$priceRec_finder->_link = Module_ApparelQuote::dbLink();
$found_recs = $priceRec_finder->find(_ALL,"`product_id`={$this->myProductId}","`qtyrange_id`,`color_id`");
$qtyFinder = new ApparelQuote_ProductPricingQtyRange();
$qtyFinder->_link = Module_ApparelQuote::dbLink();
$this->myQuantityRanges = $qtyFinder->find(_ALL,"`product_id`=$this->myProductId");
$this->myQuantityPricing = array();
foreach ($found_recs as &$r)
{
if(false) $r = new ApparelQuote_ProductPricingRecord();
if(!isset($this->myColors[$r->color_id]))
$this->myColors[$r->color_id] = true;
if(!isset($this->mySizes[$r->size_id]))
$this->mySizes[$r->size_id] = true;
if(!is_array($this->myQuantityPricing[$r->qtyrange_id]))
$this->myQuantityPricing[$r->qtyrange_id] = array();
if(!is_array($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id] = array();
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id][$r->size_id] = &$r;
}
$this->myColors = array_keys($this->myColors);
$this->mySizes = array_keys($this->mySizes);
}
}
}
$start_time = DFStdLib::exec_time();
$pmatrix = new ApparelQuote_ProductPricingMatrix_TestCase(19);
$ranges = $pmatrix->ranges();
$end_time = DFStdLib::exec_time();
$duration = $end_time - $start_time;
echo "Output generation duration was: $duration sec";
fastcgi_finish_request();
$fastcgi_finish_request_duration = DFStdLib::exec_time() - $end_time;
DFSkel::log(DFSkel::LOG_INFO,"Output generation duration was: $duration sec; fastcgi_finish_request Duration was: $fastcgi_finish_request_duration sec");
在继续调试后,我从上面缩小到以下几行:
if(!is_array($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id] = array();
这些语句正在构建从 MySQL 加载的所有数据的内存数组结构。如果我将这些注释掉,则 fastcgi_finish_request
运行大约需要 0.0001 秒。如果我不将它们注释掉,则fastcgi_finish_request
需要 7 秒以上的时间才能运行。
is_array
这实际上是这里的问题的函数调用
更改为:
if(!isset($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
解决问题。为什么是这样?