【问题标题】:in_array vs strpos for performance in phpin_array 与 strpos 在 php 中的性能
【发布时间】:2014-01-30 23:35:32
【问题描述】:

我通过 Windows 身份验证登录用户,然后将该用户的权限存储在会话变量中。我在数据库中使用分隔的权限存储方法,即:

$rights //retrieved from database 
= 'read,edit,delete,admin'

所以我的问题是我应该这样做;

//generate variable
$_SESSION['userrights'] = $rights ($rights is retrieved from database)

//use strpos to find if right is allowed
if (strpos($_SESSION['userrights'],"admin") !== false) { // do the function }

//make array of rights
$_SESSION['userrights'] = explode(',',$rights)

//use in_array to find if right is allowed
if (in_array("admin",$_SESSION['userrights'])) { // do the function }

有点强迫症问题,因为我认为对于我正在做的事情来说差异几乎可以忽略不计,但哪种方法更快(使用更少的资源)?

除了侮辱我的权利存储方法的答案外,任何答案都值得赞赏!

【问题讨论】:

  • 肯定用第二种方法。与在字符串中查找值相比,检查数组中的特定值是一种更好的方法。请注意,in_array 参数顺序是 needle,haystack,而不是 haystack,needle
  • 2:50AM 懒惰复制粘贴!感谢您的回答!
  • 为什么不将它们作为键存储在关联数组中?这应该比任何一个都快。
  • 你的意思是我可以使用 isset($_SESSION['admin']) 代替?
  • 是的,或者isset($_SESSION['userrights']['admin'])

标签: php arrays performance strpos


【解决方案1】:

strpos 是搜索文本针的最快方法,the php.net documentation for strstr()

如果您只想确定特定的 needle 是否出现在 haystack 中,请改用更快且内存占用更少的函数 strpos()1

【讨论】:

    【解决方案2】:

    证明strpos 不是最快的方法,但比in_array 更快的基准测试:

    <?php
    
    echo phpversion() . PHP_EOL;
    
    // build random array
    $array = array_fill(0, 10000, 16);
    $array = array_map('openssl_random_pseudo_bytes', $array);
    $array = array_map('bin2hex', $array);
    $array_flipped = array_flip($array);
    $string = implode($array);
    $random_keys = array_rand($array_flipped, 10);
    
    $loops = 10000;
    
    $start = microtime(true);
    for ($i = 0; $i < $loops; $i++) {
        strpos($string, $random_keys[ rand(0, 9) ]);
    }
    echo __LINE__ . ': ' . round(microtime(true) - $start, 5) . PHP_EOL;
    
    $start = microtime(true);
    for ($i = 0; $i < $loops; $i++) {
        in_array($random_keys[ rand(0, 9) ], $array);
    }
    echo __LINE__ . ': ' . round(microtime(true) - $start, 5) . PHP_EOL;
    
    $start = microtime(true);
    for ($i = 0; $i < $loops; $i++) {
        isset($array_flipped[ $random_keys[ rand(0, 9) ] ]);
    }
    echo __LINE__ . ': ' . round(microtime(true) - $start, 5) . PHP_EOL;
    
    $start = microtime(true);
    for ($i = 0; $i < $loops; $i++) {
        $array_flipped = array_flip($array);
        isset($array_flipped[ $random_keys[ rand(0, 9) ] ]);
    }
    echo __LINE__ . ': ' . round(microtime(true) - $start, 5) . PHP_EOL;
    
    ?>
    

    结果:

    5.6.31
    19: 1.11484
    25: 1.3109
    31: 0.00237
    38: 13.64204
    

    如您所见,重要的是不要在运行中翻转数组以从isset 中受益。

    【讨论】:

      【解决方案3】:

      由于我经常处理大型数据集,我会在关联数组上使用 isset!empty 并检查键,就像 @Barmar 建议的那样。这是 Intel® Core™ i3-540 (3.06 GHz) 上的快速 1M 基准测试

      $test = array("read", "edit", "delete", "admin");
      
      echo "<pre>";
      
      // --- strpos($rights,$test[$i%4]) ---
      
      $rights = 'read,edit,delete,admin';
      $mctime = microtime(true);
      for($i=0; $i<=1000000; $i++) { if (strpos($rights,$test[$i%4]) !== false) { }}
      echo '  strpos(... '.round(microtime(true)-$mctime,3)."s\n";
      
      // --- in_array($test[$i%4],$rights) ---
      
      $rights = array("read", "edit", "delete", "admin");
      $mctime = microtime(true);
      for($i=0; $i<=1000000; $i++) { if (in_array($test[$i%4],$rights)) { }}
      echo 'in_array(... '.round(microtime(true)-$mctime,3)."s\n";
      
      // --- !empty($rights[$test[$i%4]]) ---
      
      $rights = array('read' => 1, 'edit' => 1, 'delete' => 1, 'admin' => 1);
      $mctime = microtime(true);
      for($i=0; $i<=1000000; $i++) { if (!empty($rights[$test[$i%4]])) { }}
      echo '  !empty(... '.round(microtime(true)-$mctime,3)."s\n";
      
      // --- isset($rights[$test[$i%4]]) ---
      
      $rights = array('read' => 1, 'edit' => 1, 'delete' => 1, 'admin' => 1);
      $mctime = microtime(true);
      for($i=0; $i<=1000000; $i++) { if (isset($rights[$test[$i%4]])) { }}
      echo '   isset(... '.round(microtime(true)-$mctime,3)."s\n\n";
      
      echo "</pre>";
      

      获胜者是isset

        strpos(... 0.393s
      in_array(... 0.519s
        !empty(... 0.232s
         isset(... 0.209s
      

      【讨论】:

      • 性能特征来自于使用关联数组而不是列表。尽管您的基准测试略有缺陷,但您没有包括任何平衡,并且仅测试strposin_array(数组/字符串中的最后一个条目)的最坏情况。为了更公平,您应该在 $i 上使用模 4 并从数组中获取它。但是,关联数组可以更好地扩展,并且使用它们的错误结果也更快。
      • @Aidiakapi 感谢您的评论!稍微修改了一下。
      • @Jonny5 感谢您付出这么多努力来安抚我的强迫症!由于您和 Barmar 的回答,我正在使用 isset.. 非常感谢
      • 我可能遗漏了一些东西,但这个测试是否考虑到从数据库字符串中的 csv 转换为数组键所需的时间?还是认为可以忽略不计?
      • 我也想知道迈克在上面提出的问题的答案!如果你有一个文本 blob,将它分解成一个数组然后使用 isset() 会比直接在文本上使用 strpos() 更快吗?
      【解决方案4】:

      如果$_SESSION['userrights'] 存在于数据库中,您是否考虑过对数据库进行查询的可能性?您已经在执行查询以获取示例中的权限列表,为什么不查询特定的 $_SESSION['userrights'] 并检查是否返回任何行?

      【讨论】:

      • 我的印象是查询会比 strpos 或 in_array 更加密集。我已经查询了数据库并将值存储在会话 var 中,所以我有手头的值。除非我误解了,否则您是在建议我每次要检查用户是否具有一定级别的权限时都进行查询? (根据用户是否拥有一项权利,我会显示多项内容)
      • 您在页面上进行了多少次用户权限查找?
      • 申请还没有完成,但我猜现在最大应该是2/3
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      • 2016-05-14
      • 2011-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多