版本 4.7.0
发布日期:2026 年 2 月 1 日
CodeIgniter4 的 4.7.0 版本发布
内容亮点
将 PHP 最低版本要求提升至
8.2。新增实验性的 FrankenPHP Worker 模式 支持,以提升性能。
重大变更
行为变更
验证规则
regex_match 验证规则中的占位符现在必须使用双花括号。
若此前使用单括号(如 regex_match[/^{placeholder}$/]),则必须
更新为双括号:regex_match[/^{{placeholder}}$/]。
此变更旨在避免与正则表达式本身的语法产生歧义,
因为单花括号(如 {1,3})在正则中用于表示量词。
BaseModel
insertBatch() 与 updateBatch() 方法现在遵循 updateOnlyChanged 和 allowEmptyInserts 等模型设置。
此变更确保了所有插入与更新操作的处理逻辑保持一致。
主键验证
insert()、insertBatch() (禁用 useAutoIncrement 时)、update()
以及 delete() 方法现在会在执行数据库查询 之前 验证主键值。
非法的主键值将抛出 InvalidArgumentException,而非 DatabaseException。
变更内容:
异常类型: 非法主键现在会抛出带有具体错误信息的
InvalidArgumentException,而非来自数据库层的通用DatabaseException。- 验证时机:
对于
update()与delete():验证发生在beforeUpdate/beforeDelete事件 之前,且在执行任何数据库查询之前。对于
insert()与insertBatch()(禁用自动增量时):验证发生在beforeInsert事件 之后,但在执行数据库查询 之前。
- 非法值: 以下值现在被明确禁止作为主键:
null(禁用自动增量时的插入操作)0(整数零)'0'(字符串零)''(空字符串)true与false(布尔值)[](空数组)嵌套数组(如
[[1, 2]])包含上述任何非法值的数组
注意: 在需要使用原始 SQL 表达式的复杂场景下,允许使用
RawSql对象作为主键值。
此变更通过提供具体的验证消息(如 “Invalid primary key: 0 is not allowed”)提升了错误报告的准确性, 并防止非法查询进入数据库。
若主键确需允许上述某些值,可在模型中重写 validateID() 方法。
实体
Entity::hasChanged() 与 Entity::syncOriginal() 方法现在对对象和数组执行深层比较,
而非浅层比较。这意味着:
对象与数组 会经过 JSON 编码及规范化处理后再进行比较,从而能够检测出嵌套结构、对象属性及数组元素的变更。
枚举 (包括
BackedEnum和UnitEnum)会通过其对应的值或成员名进行准确追踪。DateTime 对象 (
DateTimeInterface)会使用包含时区信息的 ISO 8601 格式进行比较。集合 (
Traversable),如ArrayObject与ArrayIterator,会转换为数组进行比较。带有
__toString()方法的 值对象,在属性不可访问时(私有属性对象的后备方案),将通过其字符串表示进行比较。嵌套实体 (使用
toRawArray())、JsonSerializable对象以及带有toArray()方法的对象,将通过递归规范化实现精确的变更检测。标量值 (字符串、整数、浮点数、布尔值、null)在所有实体属性均为标量时,将继续使用直接比较优化。
此前,由于仅执行引用比较,修改对象属性或包含对象的数组不会被检测为变更。 现在,对象或数组内部状态的任何修改都能被正确识别。若代码依赖旧有的浅层比较行为,则需进行相应更新。
当 $recursive 参数为 true 时,Entity::toRawArray() 方法现在能正确转换实体数组。
此前,包含数组的属性不会被递归处理。若依赖数组不被转换的旧有行为,则需更新代码。
实体与 DataCaster
此前,即使未配置类型转换($casts = [] 为空数组),DataCaster 对象也总是会被初始化。
现在 DataCaster 改为按需创建,在未配置类型转换时将为 null。
虽然此变更通常不影响常规使用,但开发者需注意 $dataCaster 在某些情况下可能为 null。
加密处理程序
当通过 $params 参数传递加密/解密参数时,OpenSSLHandler 与 SodiumHandler
不再修改处理程序的 $key 属性。通过 $params 传递的密钥现在作为局部变量使用,
确保处理程序的状态不被改变。
变更内容:
此前,向
encrypt()或decrypt()的$params传递密钥会永久修改处理程序的内部$key属性。现在,处理程序的
$key属性仅在通过Config\Encryption创建处理程序时设置。通过$params传递的密钥仅作为临时局部变量,不会修改处理程序状态。SodiumHandler::encrypt()不再调用sodium_memzero($this->key)。此前该操作会在首次使用后 销毁加密密钥,导致处理程序无法复用。
影响:
仅当 向 encrypt() 或 decrypt() 的 $params 传递了密钥,并期望该密钥在后续操作中
持续生效时,才会受到影响。大多数用户 不受影响:
不受影响: 每次操作都通过
$params传递密钥。不受影响: 从不使用
$params,始终通过Config\Encryption配置密钥。受影响: 仅通过
$params传递过一次密钥,并期望该处理程序能记住它。
若受此影响,请通过 Config\Encryption 正确配置密钥,或向服务传递自定义配置,而非依赖 $params 的副作用。
受影响代码示例:
$config = config('Encryption');
$config->key = 'your-encryption-key';
$handler = service('encrypter', $config);
$handler->encrypt($data, 'temporary-key');
// 旧行为:$handler->key 现在变为 'temporary-key'
// 新行为:$handler->key 保持不变 ('your-encryption-key')
$handler->encrypt($moreData);
// 旧行为:会使用 'temporary-key'
// 新行为:使用默认密钥 ('your-encryption-key')
迁移说明:
如需永久使用不同的加密密钥,请在创建服务时传递自定义配置:
$config = config('Encryption');
$config->key = 'your-custom-encryption-key';
// 获取使用自定义配置的新处理程序实例(非共享)
$handler = service('encrypter', $config, false);
接口变更
注意: 若自行实现了这些接口,则需更新实现类以包含新方法,从而确保兼容性。
Cache:
CacheInterface现在包含deleteMatching()方法。Cache:
CacheInterface现在包含remember()方法。所有内置缓存处理器均通过BaseHandler继承此方法,因此无需更改。Database:
QueryInterface现在包含getOriginalQuery()方法。Images:
ImageHandlerInterface现在包含新方法:clearMetadata()。
方法签名变更
BaseModel:
cleanValidationRules()方法的$row参数类型从?array $row = null变更为array $row。PageCache:
PageCache过滤器构造函数现在接受可选的Cache配置参数:__construct(?Cache $config = null)。由此支持测试时的依赖注入。虽然扩展PageCache类的自定义构造函数在技术上属于重大变更,但由于该参数有默认值,对大多数用户没有影响。- 在多个方法中添加了
SensitiveParameter属性,以隐藏堆栈跟踪中的敏感信息。受影响的方法包括: CodeIgniter\Encryption\EncrypterInterface::encrypt()CodeIgniter\Encryption\EncrypterInterface::decrypt()CodeIgniter\Encryption\Handlers\OpenSSLHandler::encrypt()CodeIgniter\Encryption\Handlers\OpenSSLHandler::decrypt()CodeIgniter\Encryption\Handlers\SodiumHandler::encrypt()CodeIgniter\Encryption\Handlers\SodiumHandler::decrypt()CodeIgniter\HTTP\CURLRequest::setAuth()CodeIgniter\HTTP\URI::setUserInfo()CodeIgniter\Security\Security::derandomize()
- 在多个方法中添加了
- 为此前缺失原生类型的
CacheInterface方法添加了类型声明: initialize()save()delete()increment()decrement()clean()getCacheInfo()getMetaData()
- 为此前缺失原生类型的
- 为
CodeIgniter\Database\QueryInterface方法添加了原生参数及返回类型: setQuery(string $sql, mixed $binds = null, bool $setEscape = true): selfgetQuery(): stringsetDuration(float $start, ?float $end = null): selfsetError(int $code, string $error): selfswapPrefix(string $orig, string $swap): self
- 为
- 为
CodeIgniter\Debug\Toolbar方法添加了原生返回类型: prepare(): voidrespond(): void
- 为
- 此前带有
#[ReturnTypeWillChange]属性的方法已更新,包含原生返回类型: CodeIgniter\Cookie\Cookie::offsetGet($offset): bool|int|stringCodeIgniter\Entity\Entity::jsonSerialize(): arrayCodeIgniter\Files\File::getSize(): false|intCodeIgniter\I18n\TimeLegacy::setTimestamp($timestamp): staticCodeIgniter\I18n\TimeTrait::createFromFormat($format, $time, $timezone = null): staticCodeIgniter\I18n\TimeTrait::setTimezone($timezone): staticCodeIgniter\Session\Handlers\Database\PostgreHandler::gc($max_lifetime): false|intCodeIgniter\Session\Handlers\ArrayHandler::read($id): stringCodeIgniter\Session\Handlers\ArrayHandler::gc($max_lifetime): intCodeIgniter\Session\Handlers\DatabaseHandler::read($id): false|stringCodeIgniter\Session\Handlers\DatabaseHandler::gc($max_lifetime): false|intCodeIgniter\Session\Handlers\FileHandler::read($id): false|stringCodeIgniter\Session\Handlers\FileHandler::gc($max_lifetime): false|intCodeIgniter\Session\Handlers\MemcachedHandler::read($id): false|stringCodeIgniter\Session\Handlers\MemcachedHandler::gc($max_lifetime): intCodeIgniter\Session\Handlers\RedisHandler::read($id): false|stringCodeIgniter\Session\Handlers\RedisHandler::gc($max_lifetime): int
- 此前带有
属性签名变更
实体: 受保护属性
CodeIgniter\Entity\Entity::$dataCaster的类型从DataCaster变更为可为空的?DataCaster。
移除废弃项
BaseModel: 移除了已废弃的
transformDataRowToArray()方法。Cache:
CodeIgniter\Cache\CacheInterface::getMetaData()的废弃返回类型false已替换为null。CodeIgniter: 移除了已废弃的
CodeIgniter\CodeIgniter::resolvePlatformExtensions()。Entity: 移除了已废弃的
CodeIgniter\Entity\Entity::setAttributes()。请改用CodeIgniter\Entity\Entity::injectRawData()。- IncomingRequest: 移除了以下废弃方法:
CodeIgniter\HTTP\IncomingRequest\detectURI()CodeIgniter\HTTP\IncomingRequest\detectPath()CodeIgniter\HTTP\IncomingRequest\parseRequestURI()CodeIgniter\HTTP\IncomingRequest\parseQueryString()
IncomingRequest: 移除了
CodeIgniter\HTTP\IncomingRequest::setPath()中已废弃的$config参数,并将该方法可见性从public变更为private。- Session: 移除了
CodeIgniter\Session\Session中以下废弃属性: CodeIgniter\Session\Session::$sessionDriverNameCodeIgniter\Session\Session::$sessionCookieNameCodeIgniter\Session\Session::$sessionExpirationCodeIgniter\Session\Session::$sessionSavePathCodeIgniter\Session\Session::$sessionMatchIPCodeIgniter\Session\Session::$sessionTimeToUpdateCodeIgniter\Session\Session::$sessionRegenerateDestroy
- Session: 移除了
Session: 移除了已废弃的
CodeIgniter\Session\Session::stop()方法。Text 辅助函数: 移除了
random_string()函数中废弃的类型:basic、md5和sha1。
增强功能
类库
API 转换器: 提供了一种结构化的方式来为 API 响应转换数据。详见 API 转换器。
CLI: 新增
SignalTrait,为 CLI 命令提供统一的操作系统信号处理。Cache: 为 Predis 处理器新增
async与persistent配置项。Cache: 为 Redis 处理器新增
persistent配置项。Cache: 为
ResponseCache增加了对 HTTP 状态的支持。Cache: 新增
Config\Cache::$cacheStatusCodes,用于控制允许被PageCache过滤器缓存的 HTTP 状态码。默认为[](为保持向后兼容,缓存所有状态码)。推荐值:[200],即仅缓存成功响应。详见 设置 $cacheStatusCodes。Cache: 新增 APCu 缓存驱动。
CURLRequest: 新增
shareConnection配置项以更改默认共享连接。CURLRequest: 新增
dns_cache_timeout选项以更改默认 DNS 缓存超时。CURLRequest: 新增
fresh_connect选项以启用/禁用请求的新连接。DataConverter: 为数据库与实体新增
EnumCast转换器。Email: 新增对 SMTP 认证方法的选择支持。可通过
Config\Email::$SMTPAuthMethod选项进行更改。Encryption: 新增
Config\Encryption::$previousKeys配置选项以支持加密密钥轮换。当使用当前密钥解密失败时,系统会自动尝试使用旧密钥,从而在轮换加密密钥时不会丢失对旧加密数据的访问权。Image:
ImageMagickHandler已重写,现完全依赖 PHPimagick扩展。Image: 新增
ImageMagickHandler::clearMetadata()方法,用于移除图像元数据以保护隐私。ResponseTrait: 新增
paginate方法以简化分页 API 响应。详见 ResponseTrait::paginate()。Session: 为
RedisHandler新增persistent配置项。Session: 通过
PersistsConnectionTrait 为 Redis 和 Memcached 会话处理器增加了连接持久化,通过在 Worker 模式下跨请求重用连接来提升性能。Time: 新增
Time::addCalendarMonths()与Time::subCalendarMonths()方法。Time: 新增
Time::isPast()与Time::isFuture()便捷方法。详见 isPast 与 isFuture。Toolbar: 修复了调试工具栏错误注入到第三方库(如使用原生 PHP 标头而非框架 Response 对象的 Dompdf)生成的响应中的问题。
UserAgents: 扩展了
robots识别列表,涵盖了新的搜索引擎和服务爬虫。View: 增加了覆盖命名空间视图(如来自模块/包的视图)的能力,只需在 app/Views/overrides 目录下放置匹配的文件结构即可。详见 覆盖命名空间视图。
命令
新增
php spark worker:install命令,用于生成 FrankenPHP Worker 模式文件(Caddyfile 和 worker 入口点)。新增
php spark worker:uninstall命令,用于移除 Worker 模式文件。
数据库
BaseConnection: 新增
ping()方法用于检查数据库连接是否存活。OCI8 使用SELECT 1 FROM DUAL,其他驱动使用SELECT 1。BaseConnection:
reconnect()方法现在在重连前会先使用ping()检查连接状态。此前某些驱动总是无条件关闭并重连,而 OCI8 的reconnect()则不执行任何操作。异常日志: 所有数据库驱动现在统一记录数据库异常日志。此前各驱动的日志格式不一。
迁移
MigrationRunner: 增加了分布式锁支持,以防止多进程环境下的并发迁移。可通过
Config\Migrations::$lock = true启用。
HTTP
内容安全策略 (CSP)
script-src与style-src指令现在可以使用 SHA-256、SHA-384 及 SHA-512 摘要作为源表达式。- 增加了对 CSP Level 3 新关键字的支持:
'strict-dynamic''unsafe-hashes''report-sample''unsafe-allow-redirects''wasm-unsafe-eval''trusted-types-eval''report-sha256''report-sha384''report-sha512'
- 增加了对以下 CSP Level 3 指令的支持:
report-toscript-src-elemscript-src-attrstyle-src-elemstyle-src-attrworker-src
请更新 app/Config/ContentSecurityPolicy.php 中的 CSP 配置以包含这些新指令。
其他
控制器属性: 增加了对 PHP 注解的支持,以便在控制器类和方法上定义过滤器及其他元数据。详见 控制器注解。
消息变更
新增
Email.invalidSMTPAuthMethod、Email.failureSMTPAuthMethod、CLI.signals.noPcntlExtension、CLI.signals.noPosixExtension以及CLI.signals.failedSignal。废弃了
Email.failedSMTPLogin与Image.libPathInvalid。更改了
Session.missingDatabaseTable。
变更
Boot: 新增
Boot::bootWorker()方法,用于 Worker 的一次性初始化。CodeIgniter: 新增
CodeIgniter::resetForWorkerMode()方法,用于在 Worker 请求之间重置特定请求的状态。Config: 新增
app/Config/WorkerMode.php用于 Worker 模式配置(持久化服务、垃圾回收)。Cookie:
CookieInterface::EXPIRES_FORMAT已更改为D, d M Y H:i:s T,以遵循 RFC 7231 推荐格式。DatabaseConfig: 新增
Config::reconnectForWorkerMode()与Config::cleanupForWorkerMode()方法,用于 Worker 模式下的数据库连接管理。Events: 新增
Events::cleanupForWorkerMode()方法。Format: 增加了通过
Config\Format::$jsonEncodeDepth配置json_encode()最大深度的支持。Paths: 增加了通过
Paths::$envDirectory属性更改.env文件位置的支持。Services: 新增
Services::resetForWorkerMode()与Services::reconnectCacheForWorkerMode()方法。Toolbar: 在 app/Config/Toolbar.php 中新增了
$disableOnHeaders属性。Toolbar: 新增
Toolbar::reset()方法以重置调试工具栏收集器。
弃用
- ContentSecurityPolicy:
废弃了
CodeIgniter\HTTP\ContentSecurityPolicy::$nonces属性。该属性从未被使用。
- Encryption:
废弃了
CodeIgniter\Encryption\Handlers\SodiumHandler::parseParams()方法。参数现在直接在encrypt()和decrypt()方法中处理。
- Image:
废弃了配置属性
Config\Image::libraryPath。不再使用。废弃了异常方法
CodeIgniter\Images\Exceptions\ImageException::forInvalidImageLibraryPath。不再使用。
Bug 修复
Cookie:
CookieInterface::SAMESITE_STRICT、CookieInterface::SAMESITE_LAX和CookieInterface::SAMESITE_NONE常量现在改为首字母大写风格(ucfirst),以与框架其他部分的用法保持一致。Cache: 将
WincacheHandler::increment()和WincacheHandler::decrement()的返回类型更改为bool,而非mixed。Entity: 修复了调用
CodeIgniter\Entity\Entity::toArray()时总是将$_cast的值更改为true且不恢复初始值的问题。Toolbar: 修复了在启用了调试工具栏的页面上发起类 AJAX 请求(如 HTMX、Turbo、Unpoly 等)时,导致 Maximum call stack size exceeded 崩溃的问题。
请查看仓库的 CHANGELOG.md 以获取完整的 Bug 修复列表。