从 4.5.8 升级到 4.6.0

请根据你的安装方式参考对应的升级说明。

破坏性变更

异常类变更

部分类抛出的异常类已经变更。某些异常类的父类也已变更。 详情请参见 变更记录

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

Time::createFromTimestamp() 时区变更

现在,如果你没有显式传入时区, Time::createFromTimestamp() 会返回一个使用 UTC 的 Time 实例。在 v4.4.6 到 v4.6.0 之前的版本中,返回的是使用当前默认时区的 Time 实例。

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

如果你想继续使用默认时区,则需要将时区作为第二个参数传入:

use CodeIgniter\I18n\Time;

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

Time 保留微秒

在之前的版本中,Time 在某些情况下会丢失微秒。 现在这些 bug 已被修复。

由于这些修复,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(), 可能会返回日期/时间错误的 Time 实例。

该 bug 已修复,现在它的行为与 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/Kint.php
    • 已移除 Config\Kint::$richSort。v6 中的 Kint 不再使用 AbstractRenderer::SORT_FULL。如果你的代码中保留此属性,会因为常量未定义而导致运行时错误。

所有变更

以下列出了 项目空间 中所有已变更的文件; 其中很多只是注释或格式调整,不会影响运行时行为:

  • 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