【问题标题】:Checking for existence in a string with strpos使用 strpos 检查字符串中是否存在
【发布时间】:2023-03-28 17:51:01
【问题描述】:

我只见过开发人员在使用strpos 来检查子字符串是否存在时使用严格比较:

if (strpos($haystack,$needle) !== false) {

}

今天我突然想到一个可以使用is_numericins

if (is_numeric(strpos($haystack,$needle))) {

}

是否有理由使用一个而不是另一个(特别是在这个用例中)?

仔细想想,strpos 的目的是返回子字符串的位置。只有当它不存在时,它才会返回 false。位置是一个数字。因此,is_numeric 非常有资格在语义上被考虑。

【问题讨论】:

  • is_numeric 将在字符串和整数上都返回 true
  • 我的想法和这个一样,除了使用is_int( )而不是is_numeric( )

标签: php strpos


【解决方案1】:

我创建了一个基准。案例check by compare with false value 总是比check by is_numeric 快。

// Init a big string array

for($i = 0; $i < 10000; $i++){
$str[] = 'a'.rand().'b'.rand();
}

// Case comparing with false value
$time1 = microtime(true);
foreach($str as $st){
$res[] = strpos($st,rand(0, count(array('b', 'c')) - 1 )) !== false;
}
$time2 = microtime(true);

echo $time2-$time1.'<br/>';

// Case 'is_numeric'
$time3 = microtime(true);
foreach($str as $st){
$res[] = is_numeric(strpos($st,rand(0, count(array('b', 'c')) - 1 )));
}
$time4 = microtime(true);
echo $time4-$time3;


//Time 1: 
//0.018877029418945 
//0.020556926727295

//Time 2:
//0.016352891921997
//0.016934871673584

//Time 3:
//0.0121009349823
//0.01330304145813

//Time 4:
//0.017507076263428
//0.01904296875

【讨论】:

    【解决方案2】:

    我发现这个问题搜索几乎相同的问题,除了我的想法是使用is_int( ) 而不是is_numeric( )。我无法真正理解发布的基准,所以我自己做了。简而言之,is_numeric( )!== false 慢一点,is_int( )is_int( ) 快一点。就我个人而言,我觉得它比!== false 更具可读性而不是更少,所以我可能会切换到它。

    这是在 php v7.1.23 下完成的

    结果:

    0.7900s for '!== false' with hits
    4.5137s for '!== false' with misses
    
    0.9297s for 'is_numeric' with hits
    4.7509s for 'is_numeric' with misses
    
    0.6391s for 'is_int' with hits
    4.4862s for 'is_int' with misses
    

    来自代码:

    $n_times = 10000000;
    $haystack_hit = "  Certificate Name: example.com";
    $heystack_miss = "Found the following certs:";
    $needle = "Certificate Name:";
    
    $start = microtime(true);
    for($i = 0; $i < $n_times; $i++)
        {
        if (strpos($haystack_hit,$needle) !== false)
            { }
        }
    $end = microtime(true) - $start;
    echo "\n" . round($end,4) . "s for '!== false' with hits\n";
    
    $start = microtime(true);
    for($i = 0; $i < $n_times; $i++)
        {
        if (strpos($haystack_miss,$needle) !== false)
            { }
        }
    $end = microtime(true) - $start;
    echo round($end,4) . "s for '!== false' with misses\n\n";
    
    // -----
    
    $start = microtime(true);
    for($i = 0; $i < $n_times; $i++)
        {
        if ( is_numeric(strpos($haystack_hit,$needle)) )
            { }
        }
    $end = microtime(true) - $start;
    echo round($end,4) . "s for 'is_numeric' with hits\n";
    
    $start = microtime(true);
    for($i = 0; $i < $n_times; $i++)
        {
        if ( is_numeric(strpos($haystack_miss,$needle)) )
            { }
        }
    $end = microtime(true) - $start;
    echo round($end,4) . "s for 'is_numeric' with misses\n\n";
    
    // -----
    
    $start = microtime(true);
    for($i = 0; $i < $n_times; $i++)
        {
        if ( is_int(strpos($haystack_hit,$needle)) )
            { }
        }
    $end = microtime(true) - $start;
    echo round($end,4) . "s for 'is_int' with hits\n";
    
    $start = microtime(true);
    for($i = 0; $i < $n_times; $i++)
        {
        if ( is_int(strpos($haystack_miss,$needle)) )
            { }
        }
    $end = microtime(true) - $start;
    echo round($end,4) . "s for 'is_int' with misses\n";
    

    【讨论】:

      【解决方案3】:

      由于 strpos 返回整数或布尔值 false,因此可以使用 is_numeric
      问题是:
      惯用自动记录/自我描述,使用is_numeric或将返回值与布尔值进行比较? IMO,与 boolean false 相比更直观:

      $string = 'new object';
      $found = strpos($string,'new');
      
      echo (is_numeric($found)) ? 'found' : 'not found';
      echo "\n";
      # much better
      echo ($found !== false)   ? 'found' : 'not found';
      echo "\n";
      

      另外,strpos(...) !== false 被过度使用,因为它是 PHP 文档所建议的。因此,它已成为常规。

      【讨论】:

        【解决方案4】:
        1. 在这种情况下使用 strpos 是为了获得比 preg_match 更快的速度,在它之上使用 is_numeric 会通过增加更多开销来抵消这种速度优势。
        2. 使用另一个函数将 false 与其他函数分开是没有意义的,最好只使用 !== false

        没有理由为什么有人会使用 is_numeric,但它会起作用,只是速度较慢。

        关于 strpos 与 preg_match: preg_match() vs strpos() for match finding?which is the fast process strpos()/stripos() or preg_match() in php

        【讨论】:

        • 但是真的慢吗?
        • 使用两个函数比使用一个要慢。
        • 这没有意义。 Morover,那只是Premature Optimization
        • 处理===(或类似的)比较仍然需要计算能力。一项比较的一项功能可能几乎没有差异。
        【解决方案5】:

        你是对的,is_numericstrpos 一起使用。但这会使代码变得棘手,从而降低代码的可读性。

        请记住,尽管这对您来说似乎很明显,但您正在让另一个阅读您的代码的程序员思考很多事情:

        1. 干草堆里有针吗?
        2. 大海捞针在哪个位置?
        3. strpos 返回什么类型的值?
        4. 这种情况下strpos的返回值是数字吗?

        而 PHP 本身可能是一门非常棘手的语言,看看这个例子:

        if (strpos("needle in a haystack","needle")!==false) {
            echo "Needle found!<br>";
        } else {
            echo "nothing found<br>";
        }
        
        if (is_numeric(strpos("needle in a haystack","needle"))) {
            echo "Needle found!<br>";
        } else {
            echo "nothing found<br>";
        }
        
        if (is_int(strpos("needle in a haystack","needle"))) {
            echo "Needle found!<br>";
        } else {
            echo "nothing found<br>";
        }
        
        // This doesn't work since 0 == false is true
        if (strpos("needle in a haystack","needle")!=false) {
            echo "Needle found!<br>";
        } else {
            echo "nothing found<br>";
        }
        
        // But this works since "haystack" position is not 0
        if (strpos("needle in a haystack","haystack")!=false) {
            echo "Haystack found!<br>";
        } else {
            echo "nothing found<br>";
        }
        
        // This doesn't work also because "needle" is at 0, and 0 is not a truthy value
        if (strpos("needle in a haystack","needle")) {
            echo "Needle found!<br>";
        } else {
            echo "nothing found<br>";
        }
        
        // But this works again since "haystack" position is not 0, and any int that's not 0 is truthy
        if (strpos("needle in a haystack","haystack")) {
            echo "Haystack found!<br>";
        } else {
            echo "nothing found<br>";
        }
        

        恕我直言,最好的选择是使用===false==!false 比较,如the php documentation for strpos 中所述:

        警告 此函数可能返回布尔值 FALSE,但也可能返回计算结果为 FALSE 的非布尔值。请阅读有关布尔值的部分以获取更多信息。使用 === 运算符来测试这个函数的返回值。

        PD:要更好地定义“真实”,请查看this post

        【讨论】:

          猜你喜欢
          • 2013-11-12
          • 1970-01-01
          • 1970-01-01
          • 2020-04-10
          • 2018-08-07
          • 1970-01-01
          • 2020-07-30
          • 2019-04-07
          • 1970-01-01
          相关资源
          最近更新 更多