返回数组比返回数组元素更快

时间:2015-03-30 13:26:45

标签: php arrays performance

我刚刚进行了这个非常有趣的实验,结果非常令人惊讶。

测试的目的是确定获得数组元素的最佳方法,即性能方面。原因是我有一个配置类,它在关联的mufti-dimensional数组中保存设置,我不太确定我是以最好的方式获取这些值。

数据(这个问题并不是真的需要,但我只是决定将其包含在内,以便您可以看到运行测试的数据量非常合理)

$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',
        ),
    ),]
);

方法

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;
}

参数(调用函数时)

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

除了任何其他可能的缺陷并仅关注性能之外,我用10000个循环运行了50次测试。每个功能总共被调用了500000次。结果是每10000次循环的平均秒数:

  

循环:100% - 0.0381秒。返回:语言

     

平原:38% - 0.0146秒。返回:语言

     

arr:23% - 0.0088秒。返回:语言

我期待loop因为里面有逻辑而很慢,但看着其他两个人的结果我很惊讶。我期望plain是最快的,因为我从数组中返回一个元素,而相反的原因arr是最慢的,因为它返回整个数组。

鉴于实验的结果,我有两个问题。

  • 为什么arr几乎比plain快2倍?
  • 我是否还有其他方法可以胜过arr

2 个答案:

答案 0 :(得分:2)

我在评论中说过这一点,但我觉得它非常接近答案。您的问题基本上归结为2+2;为什么不比普通2;

数组只是存储在内存中的对象。要从函数返回一个对象,您将返回一个内存地址(32或64位无符号整数),这意味着只需将一个整数推入堆栈。

在返回数组的索引的情况下,该索引实际上只是表示来自数组基址的偏移量,因此每次看到方括号样式的数组访问时,在内部PHP (而不是PHP的内部C实现)正在转换'索引'在数组中将其添加到数组的内存地址中,以获取该索引处存储值的内存地址。

所以当你看到这种代码时:

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

那说:

  

找到$data的地址。然后计算$file中存储的字符串的偏移量(包括查找内存中$file的内容)。然后对$setting$key$sub执行相同的操作。最后,将所有这些偏移添加到一起以获取地址(在对象的情况下)或值(在本机数据类型的情况下)作为返回值推送到堆栈。

因此返回一个简单的数组会更快。

答案 1 :(得分:1)

这就是PHP的工作方式。您希望此处返回$data的副本。事实并非如此。

你所拥有的是一个指针(对于内存中某个特定位置的ID),它引用了数据。

您返回的内容是对数据的引用,而不是它们自己的数据。

plain方法中,首先搜索值。这个成本时间。看看this great article,其中显示了数组如何在内部工作。


有时代码说的更多的是单词。你的假设是:

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

此外,您不应该使用global,这是不好的做法。您可以将数组作为参数。

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

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