4

I am looping through several thousands of rows from a mysql result and adding them to different arrays.

I get a reference to the last element in the array to operate on (for reasons outside the scope of this question).

I.e. (just an example of the scenario)

$myarray = array();
$result = &$myarray;
$row = &$result[count($result)-1]

Of course this works, but as this thread ( Why is calling a function (such as strlen, count etc) on a referenced value so slow? ) explains , calling a function which doesnt expect a variable by reference , With a variable by reference, causes the function to make a copy of the variable to operate on.

As my $result array grows to thousands of elements , continuously calling count on it , causing copies of it being made , makes the code unusable slow.

How can I get around this - Without suggesting to not use variables by reference. Also, I cant keep separate rowcounters.

Basically I need to know how to dereference a by-reference variable (which I understand cant be done) , or some other way to get a array length ? , or a way to get a reference to the last row in an array (without popping it)

Bearing in mind the array could also be empty.

Already took me ages to find out that This is the problem , so I would really appreciate any help with solving the problem.

EDIT To everyone that says that count cannot possibly be slower than end/key: Just run this simple test to confirm

//setup array of 10 000 elements
$ar = array();
for ($i = 0 ; $i < 10000 ; $i++)
{
    $ar[] = $i;
}
//get a reference to it
$ref = &$ar;
error_log (date("Y/m/d H:i:s")." : speed test 1 \r\n",3,"debug.log");
//do 10 000 counts on the referenced array
for ($i = 0 ; $i < 10000 ; $i++)
{
    $size = count($ref);
}
error_log (date("Y/m/d H:i:s")." : speed test 2 \r\n",3,"debug.log");
//do 10 000 end/key on the referenced array
for ($i = 0 ; $i < 10000 ; $i++)
{
    reset($ref);
    end($ref);
    $size = key($ref);
}
error_log (date("Y/m/d H:i:s")." : end \r\n",3,"debug.log");

Output: 15 seconds to do the counts ... less than a second to do the end/key

2012/07/10 17:25:38 : speed test 1
2012/07/10 17:25:53 : speed test 2
2012/07/10 17:25:53 : end
Community
  • 1
  • 1
Strahd_za
  • 208
  • 2
  • 11
  • Basically you are calling &$result[int] are you using the count($result) as key? I don't understand why you would do this, could you show more code? – Mark Verkiel Jul 10 '12 at 12:32
  • 1
    `count($result)` will not create a copy of $result, as it won't modify it. – raina77ow Jul 10 '12 at 12:32
  • 1
    as far as I can see, count($result) doesn't opperate on a reference? – cypherabe Jul 10 '12 at 12:34
  • 2
    Since PHP always uses copy-on-write, I doubt it's copying the whole thing in memory and I doubt your code is slow because of this precise line. Have you debugged/profiled it to confirm that this is the problematic line? – deceze Jul 10 '12 at 12:36
  • 3
    `As my $result array grows to thousands of elements, continuously calling count on it, causing copies of it being made, makes the code unusable slow` - sigh... Did you actually profile your code to make this statement? – raina77ow Jul 10 '12 at 12:37
  • I sincerely doubt the premise of your question. Any bottleneck in performance is probably a result of your algorithm, not built-in PHP functions. – user229044 Jul 10 '12 at 12:44
  • The code I provided is just a sample to demonstrate the scenario of counting a array by reference. I narrowed the bottleneck down to the counts after finding the article I referenced in the question and I can now confirm that since I replaced the counts with end/key calls as suggested in the answers below the code is running in less than a second , where it used to take 30seconds. – Strahd_za Jul 10 '12 at 14:05
  • Swap these blocks (so count will come in the second, reset/end/key in the first one), re-run the test, behold the wonders. – raina77ow Jul 10 '12 at 14:39
  • Fair enough , although the end/key is still faster the count was. And like I said in the real code it solved the problem.. for whatever reason. I dont claim to be an expert. I had a symptom. I read a thread which suggested a problem. The "cure" to the suggested problem solved my symptoms. – Strahd_za Jul 10 '12 at 14:45

3 Answers3

3

I'm still not sure I understand why this is necessary. However, you've indexed the array as a numerical sequential array, so you can do this "trick" to get the size:

// Make sure the array pointer is at the end of the array
end($result); // Not sure if this is necessary based on your description
$size = key($result) + 1; // Get the numeric key of the last array element

Note that both end() and key() take their parameters by reference. However, I wouldn't be surprised if they're now operating on references of references, but this is something you can investigate.

user229044
  • 222,134
  • 40
  • 319
  • 330
nickb
  • 58,150
  • 12
  • 100
  • 138
1

depending on your other needs, that you mentioned but didn't descripe, maybe a few of the realy oldschool (deep level) functions coud help:

end($result); // set pointer to (current) last element
$pos = key($result); //index of the last element
$row = &$result($pos);  

edit: I type too slow :)

cypherabe
  • 2,382
  • 22
  • 34
  • Thank you very much. Just a little too slow ;) Had to accept the first correct answer... but this is exactly what I wanted and solves my problem. – Strahd_za Jul 10 '12 at 14:07
0

You should have a look to the SPL data structures. Maybe a simple SplHeap or SplDoublyLinkedList can fit to your requirements. Moreover, performances are pretty good!

Florent
  • 12,220
  • 10
  • 45
  • 58