【问题标题】:Populating a PHP array: check for index first?填充 PHP 数组:首先检查索引?
【发布时间】:2008-10-03 20:16:49
【问题描述】:

如果我深陷于循环嵌套中,我想知道其中哪一个更有效:

if (!isset($array[$key])) $array[$key] = $val;

$array[$key] = $val;

就可读代码而言,第二种形式更受欢迎。实际上,名称更长,数组是多维的。所以第一个表单在我的程序中看起来很粗糙。

但我想知道第二种形式是否会更慢。由于代码是程序中最常执行的函数之一,我想使用更快的形式。

一般来说,这段代码会以相同的“$key”值执行多次。所以在大多数情况下 $array[$key] 已经被设置了,并且 isset() 将返回 FALSE。

为那些担心我将不相同的代码视为相同的人澄清一下:就程序的这一部分而言,$val 是一个常量。直到运行时才知道,但它是在程序的早期设置的,在这里不会改变。所以这两种形式产生相同的结果。这是到达 $val 最方便的地方。

【问题讨论】:

    标签: php optimization readability


    【解决方案1】:

    对于您真正想要的数组:array_key_exists($key, $array) 而不是 isset($array[$key])

    【讨论】:

    • isset() 实际上要快得多。请参阅 PHP 在线手册中 array_key_exists 页面上的 cmets。
    • 显然 isset() 可能会产生误导,因为它返回 FALSE if $array[$key] == null: us3.php.net/manual/en/function.array-key-exists.php#83500 不会影响我的情况,但值得了解。跨度>
    • 不是你想的那样,如果它等于null,则不会设置值,但是数组键仍然存在。如果要从数组中删除某些内容,则应使用 unset() 来避免此问题。
    【解决方案2】:

    isset() 对普通变量非常快,但这里有一个数组。数组的哈希映射算法很快,但它仍然比什么都不做要花费更多的时间。

    现在,如果您设置了更多的值,第一个表单会比没有设置的值更快,这仅仅是因为它只是在不获取或设置值的情况下查找哈希。因此,这可能是一个不同点:如果您在设置的键上有更多“命中”,则选择第一种形式,如果您有更多“未命中”,则选择第二种形式。

    请注意,这两段代码完全相同。第一种形式在已经设置时不会设置某个键的值 - 它可以防止“覆盖”。

    【讨论】:

    • 如果 $val 是一个常量,那么这两段代码实际上是相同的。就我的目的而言。编辑了我的问题以澄清这一点;谢谢。
    • 不确定我是否理解您的答案:“如果您在已设置的键上有更多“命中”,请选择第二个”。你是说如果 $array[$key] 已经被设置得更频繁,我应该调用isset()吗?
    【解决方案3】:

    在尝试设置$array[$key] 之前,您是否测量过您遇到这种情况的频率?我认为对此无法给出一般性建议,因为如果实际上有很多这样的情况,则 isset 检查可能会通过避免数组上不必要的集合来节省一些时间。但是,如果这种情况很少发生,开销可能会减慢您的速度……。最好的办法是对您的实际代码进行基准测试。

    但是,请注意,这两个代码可能会导致不同的结果!如果 $array[$key] 组合的 $val 并不总是相同,则前一个代码将始终将值设置为该 $array[$key] 的第一个 $val,而后一个代码将始终将其设置为该组合的最后一个值。

    (我想你知道这一点,$val 总是与$array[$key] 相同,但有些读者可能不会。)

    【讨论】:

      【解决方案4】:

      比较的开销可能是正确的,也可能不是正确的,似乎需要更长的时间。

      在两种配置中运行脚本对性能时间有何影响?

      【讨论】:

        【解决方案5】:

        您应该检查数组,但不包括您要设置的级别。

        如果你要设置

        $anArray[ 'level1' ][ 'level2' ][ 'level3' ] = ...
        

        在设置 level3 之前,您应该确保到 level2 的路径确实存在。

        $anArray[ 'level1' ][ 'level2' ]
        

        如果您不这样做,实际上不会杀死小狗,但根据您的特定环境,它们可能会生气。

        您不必检查您实际设置的索引,因为自动设置它意味着它已被声明,但为了良好的实践,您应该确保没有任何东西被神奇地创建。

        有一个简单的方法可以做到这一点:

        <?php
        
        function create_array_path( $path, & $inArray )
        {
            if ( ! is_array( $inArray ) )
            {
                throw new Exception( 'The second argument is not an array!' );
            }
            $traversed = array();
            $current = &$inArray;
        
            foreach( $path as $subpath )
            {
                $traversed[] = $subpath;
                if ( ! is_array( $current ) )
                {
                    $current = array();
                }
                if ( ! array_key_exists( $subpath, $current ) )
                {
                    $current[ $subpath ] = '';
                }
                $current = &$current[ $subpath ];
            }
        }
        
        
        $myArray = array();
        
        create_array_path( array( 'level1', 'level2', 'level3' ), $myArray );
        
        print_r( $myArray );
        
        ?>
        

        这将输出:

            Array
            (
                [level1] => Array
                    (
                        [level2] => Array
                            (
                                [level3] => 
                            )
        
                    )
        
            )
        

        【讨论】:

          【解决方案6】:

          对 isset() 的额外函数调用几乎可以保证比任何赋值都具有更多的开销。如果第二种形式没有更快,我会感到非常惊讶。

          【讨论】:

          • PHP 手册说“isset()”是“语言结构”,而不是函数。所以我预计开销实际上可能很小。我想我得把它分析一下看看。
          【解决方案7】:

          您是否需要实际检查钥匙是否在那里?通过分配给空白数组,isset() 只会减慢循环速度。除非您对数据操作进行第二次通过,否则我强烈建议您不要进行 isset 检查。这是人口,而不是操纵。

          【讨论】:

            【解决方案8】:

            您可以查看 PHP 源代码以了解不同之处。没有检查这在以后的 PHP 版本中是否会有所不同,但在 PHP3 中,关联数组功能似乎在 php3/php3_hash.c 中。

            在函数_php3_hash_exists中,做了以下事情:

            • 密钥已散列
            • 找到正确的存储桶
            • 桶遍历,直到找到正确的项目

            函数_php3_hash_add_or_update:

            • 散列
            • 找到存储桶
            • 已行走,如果存在则覆盖现有
              • 如果不存在,则添加新的

            因此它看起来只是设置它更快,因为只有一个函数调用,这个哈希和桶查找业务只会完成一次。

            【讨论】:

              【解决方案9】:

              我是 PHP 的新手,但两者的结合可以使用三元运算符

              $array[$key] = !isset($array[$key]) ? $val : $array[$key];
              

              这是一种方法。

              【讨论】:

                猜你喜欢
                • 2021-05-13
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-05-27
                • 1970-01-01
                • 2018-01-22
                • 1970-01-01
                • 2022-11-23
                相关资源
                最近更新 更多