我刚刚进行了这个非常有趣的实验,结果非常令人惊讶。
测试的目的是确定获得数组元素的最佳方法,即性能方面。原因是我有一个配置类,它在关联的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
?答案 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;
}