优化

因为 Zephir 中的代码有时非常高级, 所以 c 编译器可能无法足够地优化此代码。

由于其 AOT (ahead-of-time) 编译器, Zephir能够在编译时优化代码, 有可能缩短其执行时间, 或减少程序所需的内存。

您可以通过传递 -f 前缀的名称来启用优化:

zephir -fstatic-type-inference -flocal-context-pass

可以通过传递 -fno- 前缀的名称来禁用优化:

zephir -fno-static-type-inference -fno-call-gatherer-pass

Optimizations also can be configured in the config file config.json as follows:

{
  "namespace": "mae",
  "name": "My Awesome Extension",
  "author": "ACME",
  "version": "1.0.0",

  "optimizations": {
    "static-type-inference": true,
    "static-type-inference-second-pass": true,
    "local-context-pass": true,
    "constant-folding": true,
    "static-constant-class-folding": true,
    "call-gatherer-pass": true,
    "check-invalid-reads": false,
    "private-internal-methods": false,
    "public-internal-methods": false,
    "public-internal-functions": true
  }
}

支持以下优化:

call-gatherer-pass

这个遍历计算在同一个方法中调用一个函数或方法的次数。 这允许编译器引入内联缓存, 以避免方法或函数查找:

class MyClass extends OtherClass
{

    public function getValue()
    {
        this->someMethod();
        this->someMethod(); // This method is called faster
    }
}

check-invalid-reads

在编译过程中, 这个标志将强制检查类型来检测无效的读取。 这可确保使用默认值 (以及内部指针) 正确定义和初始化所有变量。 一个例子:

namespace Acme;

class ForInRange
{
    public static function forEmpty(var n)
    {
        var i;
        for i in range(1, n) {
            // Do something
        }
    }
}

与之比较:

namespace Acme;

class ForInRange
{
    public static function forEmpty(var n)
    {
        var i = null;
        for i in range(1, n) {
            // Do something
        }
    }
}

就Zephir 而言, 这两个例子都是完全有效的。 不同之处在于生成的 c 代码:

zval *n;

// ...

zephir_fetch_params(1, 1, 0, &n);

与之比较:

zval *n = NULL;

// ...

zephir_fetch_params(1, 1, 0, &n);

对于任何编程语言, 始终使用默认值和类型初始化变量是一种很好的做法。 不这样做, 可能会给应用程序带来意想不到的后果, 并引入错误、内存泄漏等。 通过在config.json 中使用 check-invalid-read标志我们确保指针和它们各自的C变量被正确初始化。 Zephir 开发人员不会看到他们的代码发生更改。 这将影响生成的C代码。

关于为什么C指针需要在Stack overflow here 中无效的更多信息。

constant-folding

常量折叠是在编译时对常量表达式进行简化的过程。 启用此优化时, 将简化以下代码:

public function getValue()
{
    return (86400 * 30) / 12;
}

转换为:

public function getValue()
{
    return 216000;
}

internal-call-transformation

internal-call-transformation 需要根据其等效的 php 方法生成内部方法, 从而允许绕过这些内部方法调用的 php 用户空间。 默认情况下, 此优化处于关闭状态。

此优化为每个方法生成2个实现, 一个在 php 中公开, 一个在内部公开。

上述规定的例外情况是:

  • 只允许替换 php 方法 (例如。 我们不能这样做的 phalcon 的方法)
  • 不支持关闭 (__invoke) 和 __construct
  • 所需参数的数量必须与实际参数的数量完全匹配
  • 不能在 ZendEngine2中起作用的 (PHP 5.6)

local-context-pass

此编译传递将在堆中分配的变量移动到堆栈。 这种优化可以减少程序必须做的内存间接数。

static-constant-class-folding

此优化将替换编译时的类常量值:

class MyClass
{

    const SOME_CONSTANT = 100;

    public function getValue()
    {
        return self::SOME_CONSTANT;
    }
}

转换为:

class MyClass
{

    const SOME_CONSTANT = 100;

    public function getValue()
    {
        return 100;
    }
}

static-type-inference

这个编译过程非常重要,因为它寻找的是可能被转换为静态/基本类型的动态变量,底层编译器可以更好地对其进行优化。

下面的代码使用一组动态变量来执行一些数学计算:

public function someCalculations(var a, var b)
{
    var i = 0, t = 1;

    while i < 100 {
        if i % 3 == 0 {
            continue;
        }
        let t += (a - i), i++;
    }

    return i + b;
}

变量abi仅用于数学运算,因此可以利用其他编译通道转换为静态变量。 在此传递之后, 编译器会自动将此代码重写为:

public function someCalculations(int a, int b)
{
    int i = 0, t = 1;

    while i < 100 {
        if i % 3 == 0 {
            continue;
        }
        let t += (a - i), i++;
    }

    return i + b;
}

通过禁用此编译过程, 所有变量都将维护最初声明它们的类型, 而不进行优化。

static-type-inference-second-pass

这将启用第二个类型推断传递, 从而改进基于第一个静态类型推断传递所收集的数据所做的工作。