为什么此方法在调用 150 次时会导致内存不足

  • 本文关键字:内存不足 此方法 调用 php
  • 更新时间 :
  • 英文 :


>我有这个方法

function updateSessionVariable($objectId, $id, $file){
$fileName = basename($file);
// create the mapping for object ID to Doc info such as url
$format1 = array ($objectId  => array("id" => $id, "file" => $file));
$_SESSION["objIdtoDoc"] = $_SESSION["objIdtoDoc"] + $format1;
// now create the mapping for section ID to Object Id
if(isset($_SESSION["sectionIdToObjId"][$id])){
$_SESSION["sectionIdToObjId"][$id][] =  $_SESSION["sectionIdToObjId"][$id]+ array("objId" => $objectId, "fileName" => $fileName);
}else{
$format2 = array($id => array(array("objId" => $objectId, "fileName" => $fileName)));
$_SESSION["sectionIdToObjId"] = $_SESSION["sectionIdToObjId"] + $format2;
}
}

它本质上创建了 2 个不同的会话变量。

  • objIdtoDoc基本上是一对一的映射,其中objId是键,值是(id,file)

  • sectionIdToObjId是一对多映射,其中id是键,值是(objId, filename)数组。

我只调用此方法 158次(意味着为每个会话变量添加 158 行),它导致 php 内存不足(超过 128M)。这不可能是对的。我有一种感觉,我在这种方法中复制数据或在这种方法中做错了事情

你能指教吗? 谢谢

编辑:

感谢您的所有评论,我能够指出问题所在,似乎在 IdToObjId 部分中正在进行递归操作。

我试图实现的是这个变量 sectionIdToObjId (在方法的第二部分)

[id1]=> {("objId" => $objectId, "fileName" => $fileName)}
[id2]=> {("objId" => $objectId1, "fileName" => $fileName1)
,("objId" => $objectId2, "fileName" => $fileName2)}

等等。每次调用该方法时,它都会不断更新数组。我上面说的明显是把事情搞砸了

当你组合数组时(特别是)

if(isset($_SESSION["sectionIdToObjId"][$id])){
$_SESSION["sectionIdToObjId"][$id][] =  $_SESSION["sectionIdToObjId"][$id]+ array("objId" => $objectId, "fileName" => $fileName);
}else{
...

这部分:

$_SESSION["sectionIdToObjId"][$id][] =  

创建一个新的数组项,其中包含上一项和新数组(位于分配的右侧)。

所以如果$id = 1

//iteration 1
$_SESSION["sectionIdToObjId"][1] = [
["objId" => $objectId, "fileName" => $fileName] //new data
];
//iteration 2
$_SESSION["sectionIdToObjId"][1] = [
0 => [["objId" => $objectId, "fileName" => $fileName]], //old data
1 => ["objId" => $objectId, "fileName" => $fileName] //new data
];
//iteration 3
$_SESSION["sectionIdToObjId"][1] = [
0 => [
0 => [["objId" => $objectId, "fileName" => $fileName]],
1 => ["objId" => $objectId, "fileName" => $fileName]
],1 => [
0 => [["objId" => $objectId, "fileName" => $fileName]],
1 => ["objId" => $objectId, "fileName" => $fileName]  //old data
]
],1 => ["objId" => $objectId, "fileName" => $fileName]  //new data
];

或者类似的东西,它基本上呈指数级增长。 将其乘以 158 次迭代,是的,您可能会在其中获得十亿个数组项目。

修复它的方法很简单:

$_SESSION["sectionIdToObjId"][$id][] =  array("objId" => $objectId, "fileName" => $fileName);

那么那么

//iteration 1
$_SESSION["sectionIdToObjId"][1] = [
["objId" => $objectId, "fileName" => $fileName] //new data
];
//iteration 2
$_SESSION["sectionIdToObjId"][1] = [
["objId" => $objectId, "fileName" => $fileName], //new data
["objId" => $objectId, "fileName" => $fileName] //new data
];
//iteration 3
$_SESSION["sectionIdToObjId"][1] = [
["objId" => $objectId, "fileName" => $fileName], //new data
["objId" => $objectId, "fileName" => $fileName] //new data
["objId" => $objectId, "fileName" => $fileName] //new data
];

或者$objectId应该是唯一的

$_SESSION["sectionIdToObjId"][$id][$objectId] =  array("objId" => $objectId, "fileName" => $fileName);

那么那么

//iteration 1 - $objectId = 34
$_SESSION["sectionIdToObjId"][1] = [
34 => ["objId" => 34, "fileName" => $fileName] //new data
];
//iteration 2 - $objectId = 34 ( dupliate )
$_SESSION["sectionIdToObjId"][1] = [
34 => ["objId" => 34, "fileName" => $fileName] //new data replaces data from itteration 1
];
//iteration 3 - $objectId = 200
$_SESSION["sectionIdToObjId"][1] = [
34 => ["objId" => 34, "fileName" => $fileName] //new data
200 => ["objId" => 200, "fileName" => $fileName] //new data
];

专业提示您可能会遇到的一个问题是您可能会发现您的密钥被重置,有时在序列化它们时会使用数字密钥。我不确定会话序列化是否容易出现这种情况。 发生的情况是,当他们将数组融合到刺痛时,他们只是省略了数字键,如果我记得我在 JSON 上遇到了这个问题,像这样保存在哪里(可能有也可能没有涉及一些 MongoDB ......哈哈):

//php array
['data' => [1=>'foo', 64=>'bar']]
//json data
{"data" : [ "foo", "bar" ]}

这样当它取消编码时,编号的键就会丢失,你最终会得到

//php array
['data' => [0=>'foo', 1=>'bar']]

您可以通过将它们设置为字符串来防止这种情况

//casting using  (string)
$_SESSION["sectionIdToObjId"][(string)$id][(string)$objectId] =  array("objId" => $objectId, "fileName" => $fileName);

或者(我会做什么)

//just concatenating a string on them
$_SESSION["sectionIdToObjId"]["i".$id]["j".$objectId] =  array("objId" => $objectId, "fileName" => $fileName);

如果您这样做,请不要以相同的方式检查密钥。在第一个例子(只是投射)中,PHP不在乎它是否1"1"它以同样的方式看待它,松散的类型。

if(isset($_SESSION["sectionIdToObjId"]["i".$id])){

您的数据将如下所示

$_SESSION["sectionIdToObjId"]["i1"] = [
"j34" => ["objId" => 34, "fileName" => $fileName] //new data
"j200" => ["objId" => 200, "fileName" => $fileName] //new data
];

更新

对不起,我第一次错过了这个,你的方式你最终会得到这个:

//iteration 1 - $id was not set
$_SESSION["sectionIdToObjId"]["1"] = ["objId" => 1, "fileName" => $fileName];
//iteration 2 - $id is now set ( we overwrite the first pass ) so we lost ogjId = 1
$_SESSION["sectionIdToObjId"]["1"] = [
["objId" => 5, "fileName" => $fileName] //new data replaces data from itteration 1
];
//iteration 3 
$_SESSION["sectionIdToObjId"]["1"] = [
["objId" => 5, "fileName" => $fileName], //new data
["objId" => 10, "fileName" => $fileName] //new data
];

同样在访问此内容时,

在第一次迭代中,您有一个数组,因此$_SESSION["sectionIdToObjId"]["1"]["objId"]可以访问

foreach($_SESSION["sectionIdToObjId"]["1"] as $key=>$var )
//on first iteration key = objId, value = 1

在第二次迭代中,您具有嵌套数组$_SESSION["sectionIdToObjId"]["1"][0]["objId"]因此可以访问,请注意那里的额外[0]

foreach($_SESSION["sectionIdToObjId"]["1"] as $key=>$var )
//on first iteration key = 0, value = ['objId' => 5, ... ]

这可能会导致数据结构未按您想要的方式构建的问题,循环时,在第一种情况下会有单独的项目,但第二种情况会给你一个完整的数组。 所以你以这种方式处理 2 个结构。

我只是假设它会有多个项目。 然后它将一直像第二种情况一样,嵌套数组。

if(isset($_SESSION["sectionIdToObjId"][(string)$id])){
//define our variable as an empty array
$_SESSION["sectionIdToObjId"][(string)$id] = [];
}
//add all day long
$_SESSION["sectionIdToObjId"][(string)$id][] = ["objId" => $objectId, "fileName" => $fileName];

然后你得到这个:

$_SESSION["sectionIdToObjId"]["1"] =[
["objId"=>1 ...]
];
//instead of 
$_SESSION["sectionIdToObjId"]["1"] = ["objId"=>1 ...];

希望这是有道理的。

最后一件事PHP5.4添加了短数组语法,而不是这样做

$a = array(...);

我们可以做

$a = [ ... ];

现在,如果你看到我这样做,这就是全部。我们PHP的人很懒,我的意思是高效。

最新更新