从 4.5.8 升级到 4.6.0

请根据你的安装方式参考对应的升级指南:

重大变更

异常类变更

部分类抛出的异常类已变更,部分异常类的父类已调整。详见 更新日志

如果你的代码捕获了这些异常,请修改对应的异常类。

Time::createFromTimestamp() 时区变更

当未显式传递时区参数时,Time::createFromTimestamp() 现在返回 UTC 时区的 Time 实例。在 v4.4.6 至 v4.6.0 之前的版本中,返回的是当前设置的默认时区的 Time 实例。

此行为变更是为了与 PHP 8.4 新增的 DateTimeInterface::createFromTimestamp() 方法行为保持一致。

如需保持默认时区,需显式传递时区作为第二个参数:

use CodeIgniter\I18n\Time;

$time = Time::createFromTimestamp(1501821586, date_default_timezone_get());

Time 保留微秒

在先前版本中,Time 在某些情况下会丢失微秒。这些问题已修复。

由于修复,Time 的比较结果可能发生变化:

use CodeIgniter\I18n\Time;

$time1 = new Time('2024-01-01 12:00:00.654321');
$time2 = new Time('2024-01-01 12:00:00');

$time1->equals($time2);
// Before: true
//  After: false

在此情况下,你需要手动移除微秒:

use CodeIgniter\I18n\Time;

$time1 = new Time('2024-01-01 12:00:00.654321');
$time2 = new Time('2024-01-01 12:00:00');

// Removes the microseconds.
$time1 = Time::createFromFormat(
    'Y-m-d H:i:s',
    $time1->format('Y-m-d H:i:s'),
    $time1->getTimezone(),
);

$time1->equals($time2);
// Before: true
//  After: true

以下情况现在会保留微秒:

use CodeIgniter\I18n\Time;

$time = Time::createFromFormat('Y-m-d H:i:s.u', '2024-07-09 09:13:34.654321');
echo $time->format('Y-m-d H:i:s.u');
// Before: 2024-07-09 09:13:34.000000
//  After: 2024-07-09 09:13:34.654321
use CodeIgniter\I18n\Time;

$time = new Time('1 hour ago');
echo $time->format('Y-m-d H:i:s.u');
// Before: 2024-07-26 21:05:57.000000
//  After: 2024-07-26 21:05:57.857235

注意:表示当前时间的 Time 实例在此前版本中已保留微秒。

use CodeIgniter\I18n\Time;

$time = Time::now();
echo $time->format('Y-m-d H:i:s.u');
// Before: 2024-07-26 21:39:32.249072
//  After: 2024-07-26 21:39:32.249072

返回 int 类型的方法仍会丢失微秒:

use CodeIgniter\I18n\Time;

$time1 = new Time('2024-01-01 12:00:00');
echo $time1->getTimestamp(); // 1704110400

$time2 = new Time('2024-01-01 12:00:00.654321');
echo $time2->getTimestamp(); // 1704110400

Time::setTimestamp() 行为修正

在先前版本中,对非默认时区的 Time 实例调用 Time::setTimestamp() 可能返回错误日期/时间的实例。

此问题已修复,现在行为与 DateTimeImmutable 一致:

use CodeIgniter\I18n\Time;

// The Application Timezone is "UTC".

// Set $time1 timezone to "America/Chicago".
$time1 = Time::parse('2024-08-20', 'America/Chicago');

// The timestamp is "2024-08-20 00:00" in "UTC".
$stamp = strtotime('2024-08-20'); // 1724112000

// But $time2 timezone is "America/Chicago".
$time2 = $time1->setTimestamp($stamp);

echo $time2->format('Y-m-d H:i:s P');
// Before: 2024-08-20 00:00:00 -05:00
//  After: 2024-08-19 19:00:00 -05:00

注意:使用默认时区时行为未改变:

use CodeIgniter\I18n\Time;

// The Application Timezone is "America/Chicago".

// $time1 timezone is "America/Chicago".
$time1 = Time::parse('2024-08-20');

// The timestamp is "2024-08-20 00:00" in "America/Chicago".
$stamp = strtotime('2024-08-20'); // 1724130000

// $time2 timezone is also "America/Chicago".
$time2 = $time1->setTimestamp($stamp);

echo $time2->format('Y-m-d H:i:s P');
// Before: 2024-08-20 00:00:00 -05:00
//  After: 2024-08-20 00:00:00 -05:00

注册器的脏数据修复

为防止 注册器 的自动发现机制重复执行,当 Registrar 类被加载或实例化时,如果实例化了 Config 类(继承自 CodeIgniter\Config\BaseConfig),将会抛出 ConfigException

这是因为注册器的自动发现机制若重复执行,可能导致 Config 类属性被重复赋值。

所有 Registrar 类(所有命名空间中的 Config/Registrar.php)必须修改为在加载或实例化时不实例化任何 Config 类。

如果你使用的包/模块包含此类 Registrar 类,需要修复这些包/模块中的 Registrar 类。

以下是不再适用的代码示例:

<?php

namespace CodeIgniter\Shield\Config;

use Config\App;

class Registrar
{
    public function __construct()
    {
        $config = new App(); // Bad. When this class is instantiated, Config\App will be instantiated.

        // Does something.
    }

    public static function Pager(): array
    {
        return [
            'templates' => [
                'module_pager' => 'MyModule\Views\Pager',
            ],
        ];
    }

    public static function hack(): void
    {
        $config = config('Cache');

        // Does something.
    }
}

Registrar::hack(); // Bad. When this class is loaded, Config\Cache will be instantiated.

Session ID (SID) 变更

现在 Session 库 强制使用 PHP 默认的 32 字符 SID(每字符 4 位熵)。此变更是为了匹配 PHP 9 的行为。

即始终使用以下设置:

session.sid_bits_per_character = 4
session.sid_length = 32

先前版本遵循 PHP ini 设置。因此此变更可能改变你的 SID 长度。

如无法接受此变更,请自定义 Session 类库。

接口变更

部分接口已变更。实现这些接口的类应更新其 API 以反映变更。详见 更新日志

方法签名变更

部分方法签名已变更。继承这些方法的类应更新其 API 以反映变更。详见 更新日志

移除已弃用项

部分已弃用项已被移除。如仍在使用这些项或继承这些类,请更新代码。详见 更新日志

重大增强

过滤器变更

Filters 类已变更,允许在 before 或 after 阶段多次运行相同过滤器(使用不同参数)。

如继承 Filters 类,需根据以下变更进行调整:

  • 数组属性 $filters$filtersClasses 的结构已变更

  • 属性 $arguments$argumentsClass 已停用

  • Filters 已调整为不重复实例化相同过滤器类。如过滤器类在 before 和 after 阶段均使用,将复用同一实例

项目文件

项目空间 (根目录、app、public、writable)中的部分文件已更新。由于这些文件位于 system 范围之外,需手动干预才能更新。

可通过第三方 CodeIgniter 模块辅助合并项目空间变更:在 Packagist 上探索

内容变更

以下文件有重大变更(包含弃用或视觉调整),建议将更新版本合并至你的应用:

配置

  • app/Config/Feature.php
    • Config\Feature::$autoRoutesImproved 已变更为 true

    • 新增 Config\Feature::$strictLocaleNegotiation

  • app/Config/Routing.php
    • Config\Routing::$translateUriToCamelCase 已变更为 true

所有变更

以下是 项目空间 中所有发生变更的文件列表(多数为不影响运行的注释或格式调整):

  • app/Config/Cache.php

  • app/Config/Constants.php

  • app/Config/Database.php

  • app/Config/Feature.php

  • app/Config/Format.php

  • app/Config/Kint.php

  • app/Config/Routing.php

  • app/Config/Security.php

  • app/Views/errors/html/debug.css

  • app/Views/errors/html/error_400.php

  • preload.php

  • public/index.php

  • spark