php_nub_qq
php_nub_qq

Reputation: 16035

Returning array is faster than returning an element of the array

I just conducted this very interesting experiment and the results came out quite surprising.

The purpose of the test was to determine the best way, performance-wise, to get an element of an array. The reason is that I have a configuration class which holds settings in an associative mufti-dimensional array and I was not quite sure I was getting these values the best way possible.

Data (it is not really needed for the question, but I just decided to include it so you see it is quite a reasonable amount of data to run tests with)

$data = array( 'system' => [
    'GUI' =>
    array(
        'enabled' => true,
        'password' => '',
    ),
    'Constants' => array(
        'URL_QUERYSTRING' => true,
        'ERRORS_TO_EXCEPTIONS' => true,
        'DEBUG_MODE' => true,
    ),
    'Benchmark' =>
    array(
        'enabled' => false,
    ),
    'Translations' =>
    array(
        'db_connection' => 'Default',
        'table_name' =>
        array(
            'languages' => 'languages',
            'translations' => 'translations',
        ),
    ),
    'Spam' =>
    array(
        'honeypot_names' =>
        array(
            0 => 'name1',
            1 => 'name2',
            2 => 'name3',
            3 => 'name4',
            4 => 'name5',
            5 => 'name6',
        ),
    ),
    'Response' =>
    array(
        'supported' =>
        array(
            0 => 'text/html',
            1 => 'application/json',
        ),
    ),]
);

Methods

function plain($file, $setting, $key, $sub){
    global $data;

    return $data[$file][$setting][$key][$sub];
}

function loop(...$args){
    global $data;

    $value = $data[array_shift($args)];
    foreach($args as $arg){
        $value = $value[$arg];
    }

    return $value;
}

function arr(){
    global $data;

    return $data;
}

Parameters (when calling the functions)

loop('system', 'Translations', 'table_name', 'languages');
plain('system', 'Translations', 'table_name', 'languages');
arr()['system']['Translations']['table_name']['languages'];

Leaving aside any other possible flaws and focusing on performance only, I ran 50 tests with 10000 loops. Each function has been called 500000 times in total. The results are in average seconds per 10000 loops:

loop: 100% - 0.0381 sec. Returns: languages

plain: 38% - 0.0146 sec. Returns: languages

arr: 23% - 0.0088 sec. Returns: languages

I was expecting loop to be quite slow because there is logic inside, but looking at the results of the other two I was pretty surprised. I was expecting plain to be the fastest because I'm returning an element from the array and for the opposite reason arr to be the slowest because it returns the whole array.

Given the outcome of the experiment I have 2 questions.

Upvotes: 2

Views: 95

Answers (2)

Jeff Lambert
Jeff Lambert

Reputation: 24661

I said this in the comment, but I decided it's pretty close to an answer. Your question basically boils down to why is 2+2; not faster than just plain 2;

Arrays are just objects stored in memory. To return an object from a function, you return a memory address (32 or 64 bit unsigned integer), which implies nothing more than pushing a single integer onto the stack.

In the case of returning an index of an array, that index really just represents an offset from the base address of the array, so everytime you see a square bracket-style array access, internally PHP (rather the internal C implementation of PHP) is converting the 'index' in the array into an integer that it adds to the memory address of the array to get the memory address of the stored value at that index.

So when you see this kind of code:

return $data[$file][$setting][$key][$sub];

That says:

Find me the address of $data. Then calculate the offset that the string stored in $file is (which involves looking up what $file is in memory). Then do the same for $setting, $key, and $sub. Finally, add all of those offsets together to get the address (in the case of objects) or the value (in the case of native data types) to push on to the stack as a return value.

It should be no surprise then that returning a simple array is quicker.

Upvotes: 2

Christian Gollhardt
Christian Gollhardt

Reputation: 17014

That's the way PHP works. You expect, that a copy of $data is returned here. It is not.

What you acutaly have, is a pointer (Something like an ID to a specific place in the memory), which reference the data.

What you return, is the reference to the data, not the data them self.

In the plain method, you search for the value first. This cost time. Take a look at this great article, which show, how arrays are working internal.


Sometimes Code say's more then words. What you assume is:

function arr(){
    global $data;
    //create a copy
    $newData = $data;
    //return reference to $newData
    return $newData;
}

Also you should not use global, that is bad practise. You can give your array as a parameter.

//give a copy of the data, slow
function arr($data) {
    return $data;
}

//give the reference, fast
function arr(&$data) {
    return $data;
}

Upvotes: 1

Related Questions