在哪里放置将多次访问的具有常量值的数组?5 菲律宾比索7.0 菲律宾比索7.1 菲律宾比索

2022-08-30 13:42:32

我有一些数组存储一些3D打印机命令的可能参数。我用它来检查命令是否合法。我对应该把这些数组放在哪里感到困惑。这些数组将仅在 formatcheck 函数中访问,并且该函数将被多次调用,因为有数千个命令需要检查。我应该将它们作为变量放在 formatcheck 函数中,还是作为私有静态变量放在 formatcheck 函数所在的类的开头?

public function checkFileGcodeFormat()
{
    $Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
    $Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
    $Ts = array(0, 1);
    if (
      !(
        $this->hasM() 
        && $this->hasNoXYZ() 
        && in_array($this->M, $this->Ms)
      ) 
      ||
      (
        $this->hasG() 
        && in_array($this->G, $this->Gs)
      ) 
      ||
      (
        $this->hasT() 
        && $this->hasNoXYZ() 
        && in_array($this->T, $this->Ts)
      ) 
    )
        return false;
    else
        return true;
}   

艺术

private static $Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
private static $Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
private static $Ts = array(0, 1);
...
...
public function checkFileGcodeFormat()
{
    if (
      !(
        $this->hasM() 
        && $this->hasNoXYZ() 
        && in_array($this->M, $this->Ms)
      ) 
      ||
      (
        $this->hasG() 
        && in_array($this->G, $this->Gs)
      ) 
      ||
      (
        $this->hasT() 
        && $this->hasNoXYZ() 
        && in_array($this->T, $this->Ts)
      ) 
    )
        return false;
    else
        return true;
}

答案 1

TL;DR:使用类常量以获得最佳性能(请参阅答案末尾)。

让我们看一下不同版本的性能特征(以及原因):

5 菲律宾比索

静态属性中的数组是在编译时非常快速地创建的,无需 VM 参与。访问静态属性比访问普通变量慢一点,但仍然比每次运行时重新创建数组快得多。

在任何情况下,普通函数中的数组都会在每次运行时重新创建。在 VM 中运行时创建意味着每个元素都是在单独的操作码中逐个添加的,这意味着相当多的开销(特别是如果数组大于 1-2 个元素)。

7.0 菲律宾比索

普通函数中的数组[一般]的创建速度更快,因为数组创建速度通常会加快(HashTable处理中的优化)。如果全部是常量值,则会将其缓存在内部常量值数组中,但在每次访问时都会重复。然而,执行直接的高度专业化的复制操作显然比像 PHP 5 那样逐个将元素添加到数组中更快。

Opcache在内部将它们标记为不可变,这允许直接访问[因此您可以使用opcache获得全速]。(另请参见 https://blog.blackfire.io/php-7-performance-improvements-immutable-arrays.html)

7.1 菲律宾比索

数组本身始终缓存在内部常量值数组中,具有写入时复制语义。

现在,使用静态属性的速度较慢,因为查找静态属性的性能不如对变量的简单写入。[直接访问变量没有额外的开销。


另请注意,从 PHP 5.6 开始,您可以使用数组的值声明(类)常量。PHP 7.1 允许直接替换同一类的类常量,并将数组直接添加到内部常量值数组中,以便直接与in_array一起使用。

即最快的代码是(至少7.1):

private const Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
private const Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
private const Ts = array(0, 1);
...
...
public function checkFileGcodeFormat()
{
    if (! ($this->hasM() && $this->hasNoXYZ() && in_array($this->M, self::Ms)) || ($this->hasG() && in_array($this->G, self::Gs)) || ($this->hasT() && $this->hasNoXYZ() && in_array($this->T, self::Ts)) )
        return false;
    else
        return true;
}

答案 2

我认为定义数组属性更有意义,因为在每次调用时都会创建在方法中定义的数组。

但我想再说一点。如果您有相当大的数组来查找值,那么如何构建它们更为重要。我会建议这个:

array(
    82 => true,
    83 => true,
    84 => true,
    104 => true,
    106 => true,
    107 => true,
    109 => true,
    140 => true,
    190 => true
);

array(
    0 => true,
    1 => true,
    20 => true,
    21 => true,
    28 => true,
    90 => true,
    91 => true,
    92 => true
);

array(
    0 => true,
    1 => true
);

具有此结构,您可以使用 isset () 而不是 in_array ()。O(1)O(n)

以下是有关定位in_array的其他一些问题:

以下是一些带有基准的帖子:

最后一个是相当古老的,但我认为这个比例成立。

所以总结一下。当您使用 isset 时,搜索时间是恒定的(它实际上可能会有所不同,但可以忽略)。使用in_array搜索时间取决于元素位置(以及数组大小等)。即使在小型阵列上,设置也能更快地工作。