# 基准测试

CodeIgniter 提供两个独立的工具，用于基准测试代码并对比不同方案： Timer 和 Iterator。Timer 用于轻松计算脚本执行过程中任意两个时间点之间的耗时。Iterator 则支持设置多种代码变体并运行测试，通过记录性能和内存统计数据，辅助筛选最优版本。

Timer 类始终保持启用状态。该类从框架启动瞬间开始计时，直至向用户发送响应前结束，从而实现对整个系统执行过程的高精度计时。

## 使用 Timer

使用 Timer，可以测量应用执行过程中两个时刻之间的时间间隔。这样可以 轻松测量应用不同方面的性能。所有测量通过 `start()` 和 `stop()` 方法完成。

### Timer::start()

`start()` 方法接受一个参数：计时器的名称。可以使用任意字符串作为 计时器名称。该名称仅用于后续引用，以便区分各个测量项：

    <?php

    $benchmark = service('timer');
    $benchmark->start('render view');

### Timer::stop()

`stop()` 方法接受要停止的计时器名称作为唯一参数：

    <?php

    $benchmark->stop('render view');

名称不区分大小写，但必须与启动计时器时使用的名称一致。

### timer()

另外，也可以使用 全局函数 `timer()` 来启动 和停止计时器：

    <?php

    // Start the timer
    timer('render view');
    // Stop a running timer,
    // if one of this name has been started
    timer('render view');

### Timer::record()

Added in version 4.3.0.

从 v4.3.0 开始，如果基准测试的代码块非常小，还可以使用 `record()` 方法。该方法接受 一个无参数的可调用对象并测量其执行时间。方法 `start()` 和 `stop()` 会在 函数调用前后自动执行。

    <?php

    $benchmark->record('slow_function', static function () { slow_function('...'); });

    /*
     * Same as:
     *
     * $benchmark->start('slow_function');
     * slow_function('...');
     * $benchmark->stop('slow_function');
    */

也可以返回可调用对象的返回值，以便进一步处理。

    <?php

    $length = $benchmark->record('string length', static fn () => strlen('CI4'));

    /*
     * $length = 3
     *
     * Same as:
     *
     * $benchmark->start('string length');
     * $length = strlen('CI4');
     * $benchmark->stop('string length');
    */

向 `timer()` 传递可调用对象作为第二个参数时，也提供相同的功能。

    <?php

    $length = timer('string length', static fn () => strlen('CI4'));

    /*
     * $length = 3
     *
     * Same as:
     *
     * timer('string length');
     * $length = strlen('CI4');
     * timer('string length');
    */

### 查看基准测试记录点

应用运行时，所有设置的计时器都会由 Timer 类收集。但 不会自动显示这些记录。可以通过调用 `getTimers()` 方法获取所有计时器。 该方法返回一个包含基准测试信息的数组，包括起始时间、结束时间和持续时间：

    <?php

    $timers = $benchmark->getTimers();
    /*
     * Produces:
     * [
     *     'render view'  => [
     *         'start'    => 1234567890,
     *         'end'      => 1345678920,
     *         'duration' => 15.4315, // number of seconds
     *     ]
     * ]
     */

可以通过传递唯一参数来更改计算持续时间的精度，该参数指定要显示的小数位数。 默认值是小数点后 4 位：

    <?php

    $timers = $benchmark->getTimers(6);

计时器会自动显示在 Debug 工具栏 中。

### 显示执行时间

虽然 `getTimers()` 方法会提供项目中所有计时器的原始数据，但也可以获取 单个计时器的持续时间（秒），使用 `getElapsedTime()` 方法。第一个参数是要显示的 计时器名称。第二个参数是要显示的小数位数。默认值为 4：

    <?php

    echo timer()->getElapsedTime('render view');
    // Displays: 0.0234

## 使用 Iterator

Iterator 是一个简单的工具，用于尝试多种解决方案的变体， 查看速度差异和不同的内存使用模式。可以添加任意数量的"任务"供 运行，该类会将任务运行数百或数千次，以更清晰地了解性能表现。 然后可以获取结果并在脚本中使用，或以 HTML 表格形式显示。

### 创建要运行的任务

任务在闭包中定义。任务产生的任何输出都会被自动丢弃。任务通过 `add()` 方法添加到 Iterator 类。第一个参数是用于引用 此测试的名称。第二个参数是闭包本身：

    <?php

    $iterator = new \CodeIgniter\Debug\Iterator();

    $iterator->add('double', static function ($word = 'little') {
        "Some basic {$word} string test.";
    });

### 运行任务

添加要运行的任务后，可以使用 `run()` 方法循环执行任务多次。 默认情况下，每个任务运行 1000 次。对于大多数简单测试，这已经 足够。如果需要运行更多次数，可以将次数作为第一个参数传递：

    <?php

    // Run the tests 3000 times.
    $htmlTable = $iterator->run(3000);

运行完成后，将返回包含测试结果的 HTML 表格。 如果不需要结果，可以将 `false` 作为第二个参数传递：

    <?php

    // Returns null.
    $iterator->run(1000, false);