Push 100,000 elements onto a PHP array() where each element is a four element associative array (a hash in Perl speak). Here’s the data being pushed:
array( 'owner' => 100, 'host' => 'www.example.com.co.uk', 'path' => '/this/is/an/example/path.html', 'hostkey' => '1111' )
The memory grows by over 80 megabytes.
Pushing takes less than a second or two but shifting off the first 1000 elements takes over 17 seconds on my machine.
Now take that same data and create a basic FIFO class that has push() and shift() methods. Use pack() and unpack() to store the data in a long string. Total time to push 100,000 and shift the first 1000 elements is around 1 second. Total memory is 7 megabytes which is less than 10% of PHP’s internal array()’s consumption.
PHP’s splFixedArray class which is advertised as mainly having a speed advantage doesn’t fair much better. With a fixed array created of 100,000 elements and loading and unloading the same associative array() it grows by 75 megs but is very fast at half a second. Just for fun I pushed 100,000 elements on an splFixedArray which are simply the values of the test associative array concatenated into a string and it’s still weighs in at 13 megabytes.
Here’s the FIFO class:
class wfArray {
private $data = "";
private $shiftPtr = 0;
public function __construct($keys){
$this->keys = $keys;
}
public function push($val){ //associative array with keys that match those given to constructor
foreach($this->keys as $key){
$this->data .= pack('N', strlen($val[$key])) . $val[$key];
}
}
public function shift(){
$arr = array();
if(strlen($this->data) < 1){ return null; }
foreach($this->keys as $key){
$len = unpack('N', substr($this->data, $this->shiftPtr, 4));
$len = $len[1];
$arr[$key] = substr($this->data, $this->shiftPtr + 4, $len);
$this->shiftPtr += 4 + $len;
}
return $arr;
}
}
Here’s the test script using the FIFO class with the array() tests commented out.
require_once('wfArray.php');
error_reporting(E_ALL);
$p1 = memory_get_peak_usage();
$stime = microtime(true);
//$arr = array();
$arr = new wfArray(array('owner', 'host', 'path', 'hostkey'));
for($i = 0; $i < 100000; $i++){
//array_push($arr, array(
$arr->push(array(
'owner' => 100,
'host' => 'www.example.com.co.uk',
'path' => '/this/is/an/example/path.html',
'hostkey' => '1111'
));
if($i % 1000 == 0){ echo $i . "\n"; }
}
$i = 0;
while($elem = $arr->shift()){
//while($elem = array_shift($arr)){
$i++;
if($i > 1000){ break; }
if(! ($elem['owner'] == 100 && $elem['host'] == 'www.example.com.co.uk' && $elem['path'] == '/this/is/an/example/path.html' && $elem['hostkey'] == '1111')){
die("Problem");
}
}
echo "\nTotal time: " . sprintf('%.3f', microtime(true) - $stime) . "\n";
$p2 = memory_get_peak_usage();
echo "Grew: " . ($p2 - $p1) . "\n";
Have you tried SplQueue?
See this: https://bugs.php.net/bug.php?id=18829
Commented on June 19, 2012 at 8:00 pm
It’s “fare much better”.
This class has a very limited set of use cases… yeah, if you take most of the features out of a structure with a lot of features, it will probably be leaner! Can’t think of many cases where I could actually use it, and we use arrays quite a lot.
Commented on June 19, 2012 at 8:17 pm
A bit scary indeed. But I don’t see anyone putting 100,000 items in an array really either.
Commented on June 19, 2012 at 9:53 pm
What structure should then be used in PHP for medium-size (100k-1m) datasets? This isn’t speaking about large data, processing a list of 100.000 numbers was a reasonably common task even in 1990.
Commented on June 19, 2012 at 11:26 pm
yes, it faster. but you would miss all of php array advantages because actually you store data as string.
what about this scenario :
shifting $array then get value of $array[99999] ?
i think the result would be the same as normal php array operation.
i never use array_shift, cause it can be tricked by index manipulation when accessing array elements.
faster and consume less memory
Commented on July 11, 2013 at 9:41 pm
This is great, but what if we want to retrieve data when using this pack technique?
Commented on September 12, 2013 at 8:36 pm