diff --git a/rector.php b/rector.php
index 14a079e0ab04..8fd3ab275345 100644
--- a/rector.php
+++ b/rector.php
@@ -53,6 +53,7 @@
use Rector\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedStrictParamTypeRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
use Rector\TypeDeclaration\Rector\Closure\AddClosureVoidReturnTypeWhereNoReturnRector;
+use Rector\TypeDeclaration\Rector\Closure\ClosureReturnTypeRector;
use Rector\TypeDeclaration\Rector\Empty_\EmptyOnNullableObjectToInstanceOfRector;
use Rector\TypeDeclaration\Rector\Function_\AddFunctionVoidReturnTypeWhereNoReturnRector;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector;
@@ -217,6 +218,7 @@
AddFunctionVoidReturnTypeWhereNoReturnRector::class,
AddMethodCallBasedStrictParamTypeRector::class,
TypedPropertyFromAssignsRector::class,
+ ClosureReturnTypeRector::class,
])
->withConfiguredRule(StringClassNameToClassConstantRector::class, [
// keep '\\' prefix string on string '\Foo\Bar'
diff --git a/system/Database/OCI8/Builder.php b/system/Database/OCI8/Builder.php
index 4423a5243a81..24a6bb53b07c 100644
--- a/system/Database/OCI8/Builder.php
+++ b/system/Database/OCI8/Builder.php
@@ -109,12 +109,12 @@ protected function _replace(string $table, array $keys, array $values): string
{
$fieldNames = array_map(static fn ($columnName) => trim($columnName, '"'), $keys);
- $uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
+ $uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return ($index->type === 'PRIMARY') && $hasAllFields;
});
- $replaceableFields = array_filter($keys, static function ($columnName) use ($uniqueIndexes) {
+ $replaceableFields = array_filter($keys, static function ($columnName) use ($uniqueIndexes): bool {
foreach ($uniqueIndexes as $index) {
if (in_array(trim($columnName, '"'), $index->fields, true)) {
return false;
@@ -344,7 +344,7 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
if (empty($constraints)) {
$fieldNames = array_map(static fn ($columnName) => trim($columnName, '"'), $keys);
- $uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
+ $uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return ($index->type === 'PRIMARY' || $index->type === 'UNIQUE') && $hasAllFields;
diff --git a/system/Database/OCI8/PreparedQuery.php b/system/Database/OCI8/PreparedQuery.php
index a6b6c73c0348..0d20619413d7 100644
--- a/system/Database/OCI8/PreparedQuery.php
+++ b/system/Database/OCI8/PreparedQuery.php
@@ -113,7 +113,7 @@ public function parameterize(string $sql): string
// Track our current value
$count = 0;
- return preg_replace_callback('/\?/', static function ($matches) use (&$count) {
+ return preg_replace_callback('/\?/', static function ($matches) use (&$count): string {
return ':' . ($count++);
}, $sql);
}
diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php
index 90b53b04e9da..196535729efe 100644
--- a/system/Database/Postgre/Builder.php
+++ b/system/Database/Postgre/Builder.php
@@ -368,7 +368,7 @@ protected function _updateBatch(string $table, array $keys, array $values): stri
$sql .= 'WHERE ' . implode(
' AND ',
array_map(
- static function ($key, $value) use ($table, $alias, $that) {
+ static function ($key, $value) use ($table, $alias, $that): string|RawSql {
if ($value instanceof RawSql && is_string($key)) {
return $table . '.' . $key . ' = ' . $value;
}
@@ -463,7 +463,7 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
$constraints = $this->QBOptions['constraints'] ?? [];
if (empty($constraints)) {
- $allIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
+ $allIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return ($index->type === 'UNIQUE' || $index->type === 'PRIMARY') && $hasAllFields;
@@ -575,7 +575,7 @@ protected function _deleteBatch(string $table, array $keys, array $values): stri
$sql .= 'WHERE ' . implode(
' AND ',
array_map(
- static function ($key, $value) use ($table, $alias, $that) {
+ static function ($key, $value) use ($table, $alias, $that): RawSql|string {
if ($value instanceof RawSql) {
return $value;
}
diff --git a/system/Database/Postgre/PreparedQuery.php b/system/Database/Postgre/PreparedQuery.php
index 6425297d2e97..cabca91bb662 100644
--- a/system/Database/Postgre/PreparedQuery.php
+++ b/system/Database/Postgre/PreparedQuery.php
@@ -119,7 +119,7 @@ public function parameterize(string $sql): string
// Track our current value
$count = 0;
- return preg_replace_callback('/\?/', static function () use (&$count) {
+ return preg_replace_callback('/\?/', static function () use (&$count): string {
$count++;
return "\${$count}";
diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php
index a6d0b8e85ccd..fcc0b170084f 100644
--- a/system/Database/SQLSRV/Builder.php
+++ b/system/Database/SQLSRV/Builder.php
@@ -699,7 +699,7 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
if (empty($constraints)) {
$tableIndexes = $this->db->getIndexData($table);
- $uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames) {
+ $uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return $index->type === 'PRIMARY' && $hasAllFields;
@@ -707,7 +707,7 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
// if no primary found then look for unique - since indexes have no order
if ($uniqueIndexes === []) {
- $uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames) {
+ $uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return $index->type === 'UNIQUE' && $hasAllFields;
diff --git a/system/Database/SQLite3/Builder.php b/system/Database/SQLite3/Builder.php
index 87bc4d73a885..8a5d43b6751a 100644
--- a/system/Database/SQLite3/Builder.php
+++ b/system/Database/SQLite3/Builder.php
@@ -145,7 +145,7 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
if (empty($constraints)) {
$fieldNames = array_map(static fn ($columnName) => trim($columnName, '`'), $keys);
- $allIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
+ $allIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return ($index->type === 'PRIMARY' || $index->type === 'UNIQUE') && $hasAllFields;
diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php
index ee9f829b05b8..1a923a35516b 100644
--- a/system/Debug/Toolbar/Collectors/Database.php
+++ b/system/Debug/Toolbar/Collectors/Database.php
@@ -148,7 +148,7 @@ protected function formatTimelineData(): array
public function display(): array
{
$data = [];
- $data['queries'] = array_map(static function (array $query) {
+ $data['queries'] = array_map(static function (array $query): array {
$isDuplicate = $query['duplicate'] === true;
$firstNonSystemLine = '';
diff --git a/system/Events/Events.php b/system/Events/Events.php
index a06bd7903e69..ad8efed62f9e 100644
--- a/system/Events/Events.php
+++ b/system/Events/Events.php
@@ -84,7 +84,7 @@ public static function initialize()
$files = service('locator')->search('Config/Events.php');
}
- $files = array_filter(array_map(static function (string $file) {
+ $files = array_filter(array_map(static function (string $file): false|string {
if (is_file($file)) {
return realpath($file) ?: $file;
}
diff --git a/system/HTTP/ContentSecurityPolicy.php b/system/HTTP/ContentSecurityPolicy.php
index 7582bc467733..d0dda0ad5752 100644
--- a/system/HTTP/ContentSecurityPolicy.php
+++ b/system/HTTP/ContentSecurityPolicy.php
@@ -713,7 +713,7 @@ protected function generateNonces(ResponseInterface $response)
$pattern = '/(' . preg_quote($this->styleNonceTag, '/')
. '|' . preg_quote($this->scriptNonceTag, '/') . ')/';
- $body = preg_replace_callback($pattern, function ($match) {
+ $body = preg_replace_callback($pattern, function ($match): string {
$nonce = $match[0] === $this->styleNonceTag ? $this->getStyleNonce() : $this->getScriptNonce();
return "nonce=\"{$nonce}\"";
diff --git a/system/HTTP/Negotiate.php b/system/HTTP/Negotiate.php
index 67a03a38014d..4f218347738d 100644
--- a/system/HTTP/Negotiate.php
+++ b/system/HTTP/Negotiate.php
@@ -233,7 +233,7 @@ public function parseHeader(string $header): array
}
// Sort to get the highest results first
- usort($results, static function ($a, $b) {
+ usort($results, static function ($a, $b): int {
if ($a['q'] === $b['q']) {
$aAst = substr_count($a['value'], '*');
$bAst = substr_count($b['value'], '*');
diff --git a/system/Helpers/Array/ArrayHelper.php b/system/Helpers/Array/ArrayHelper.php
index b9c356d381c1..f3eff03ba7a2 100644
--- a/system/Helpers/Array/ArrayHelper.php
+++ b/system/Helpers/Array/ArrayHelper.php
@@ -307,7 +307,7 @@ public static function recursiveCount(array $array, int $counter = 0): int
*/
public static function sortValuesByNatural(array &$array, $sortByIndex = null): bool
{
- return usort($array, static function ($currentValue, $nextValue) use ($sortByIndex) {
+ return usort($array, static function ($currentValue, $nextValue) use ($sortByIndex): int {
if ($sortByIndex !== null) {
return strnatcmp((string) $currentValue[$sortByIndex], (string) $nextValue[$sortByIndex]);
}
diff --git a/system/Helpers/url_helper.php b/system/Helpers/url_helper.php
index d68fea2aad7d..fcfce09f5697 100644
--- a/system/Helpers/url_helper.php
+++ b/system/Helpers/url_helper.php
@@ -351,7 +351,15 @@ function safe_mailto(string $email, string $title = '', $attributes = ''): strin
function auto_link(string $str, string $type = 'both', bool $popup = false): string
{
// Find and replace any URLs.
- if ($type !== 'email' && preg_match_all('#(\w*://|www\.)[a-z0-9]+(-+[a-z0-9]+)*(\.[a-z0-9]+(-+[a-z0-9]+)*)+(/([^\s()<>;]+\w)?/?)?#i', $str, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
+ if (
+ $type !== 'email'
+ && preg_match_all(
+ '#([a-z][a-z0-9+\-.]*://|www\.)[a-z0-9]+(-+[a-z0-9]+)*(\.[a-z0-9]+(-+[a-z0-9]+)*)+(/([^\s()<>;]+\w)?/?)?#i',
+ $str,
+ $matches,
+ PREG_OFFSET_CAPTURE | PREG_SET_ORDER
+ )
+ ) {
// Set our target HTML if using popup links.
$target = ($popup) ? ' target="_blank"' : '';
@@ -370,7 +378,15 @@ function auto_link(string $str, string $type = 'both', bool $popup = false): str
}
// Find and replace any emails.
- if ($type !== 'url' && preg_match_all('#([\w\.\-\+]+@[a-z0-9\-]+\.[a-z0-9\-\.]+[^[:punct:]\s])#i', $str, $matches, PREG_OFFSET_CAPTURE)) {
+ if (
+ $type !== 'url'
+ && preg_match_all(
+ '#([\w\.\-\+]+@[a-z0-9\-]+\.[a-z0-9\-\.]+[^[:punct:]\s])#i',
+ $str,
+ $matches,
+ PREG_OFFSET_CAPTURE
+ )
+ ) {
foreach (array_reverse($matches[0]) as $match) {
if (filter_var($match[0], FILTER_VALIDATE_EMAIL) !== false) {
$str = substr_replace($str, safe_mailto($match[0]), $match[1], strlen($match[0]));
diff --git a/system/Router/Router.php b/system/Router/Router.php
index e20f4fff55bb..247f0de6b6b8 100644
--- a/system/Router/Router.php
+++ b/system/Router/Router.php
@@ -434,7 +434,7 @@ protected function checkRoutes(string $uri): bool
// Is this route supposed to redirect to another?
if ($this->collection->isRedirect($routeKey)) {
// replacing matched route groups with references: post/([0-9]+) -> post/$1
- $redirectTo = preg_replace_callback('/(\([^\(]+\))/', static function () {
+ $redirectTo = preg_replace_callback('/(\([^\(]+\))/', static function (): string {
static $i = 1;
return '$' . $i++;
diff --git a/system/View/Parser.php b/system/View/Parser.php
index bbeb00f757c0..6600b0178369 100644
--- a/system/View/Parser.php
+++ b/system/View/Parser.php
@@ -534,7 +534,7 @@ protected function replaceSingle($pattern, $content, $template, bool $escape = f
$content = (string) $content;
// Replace the content in the template
- return preg_replace_callback($pattern, function ($matches) use ($content, $escape) {
+ return preg_replace_callback($pattern, function ($matches) use ($content, $escape): string {
// Check for {! !} syntax to not escape this one.
if (
str_starts_with($matches[0], $this->leftDelimiter . '!')
diff --git a/tests/system/Commands/Utilities/NamespacesTest.php b/tests/system/Commands/Utilities/NamespacesTest.php
index c32d9280aef4..ffdfa0ddcf8d 100644
--- a/tests/system/Commands/Utilities/NamespacesTest.php
+++ b/tests/system/Commands/Utilities/NamespacesTest.php
@@ -42,7 +42,7 @@ protected function tearDown(): void
*/
protected function getBuffer()
{
- return preg_replace_callback('/(\|\s*[^|]+\s*\|\s*)(.*?)(\s*\|\s*[^|]+\s*\|)/', static function (array $matches) {
+ return preg_replace_callback('/(\|\s*[^|]+\s*\|\s*)(.*?)(\s*\|\s*[^|]+\s*\|)/', static function (array $matches): string {
$matches[2] = str_replace(DIRECTORY_SEPARATOR, '/', $matches[2]);
return $matches[1] . $matches[2] . $matches[3];
diff --git a/tests/system/DataConverter/DataConverterTest.php b/tests/system/DataConverter/DataConverterTest.php
index 3383bbfdc102..36bae4e89ddc 100644
--- a/tests/system/DataConverter/DataConverterTest.php
+++ b/tests/system/DataConverter/DataConverterTest.php
@@ -606,7 +606,7 @@ public function testReconstructObjectWithClosure(): void
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
- $reconstructor = static function ($array) {
+ $reconstructor = static function ($array): User {
$user = new User();
$user->fill($array);
@@ -703,7 +703,7 @@ public function testExtractWithClosure(): void
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
- $extractor = static function ($obj) {
+ $extractor = static function ($obj): array {
$array['id'] = $obj->id;
$array['name'] = $obj->name;
$array['created_at'] = $obj->created_at;
diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php
index d76e35583305..643096c482cb 100644
--- a/tests/system/Debug/TimerTest.php
+++ b/tests/system/Debug/TimerTest.php
@@ -144,7 +144,7 @@ public function testRecordFunctionNoReturn(): void
public function testRecordFunctionWithReturn(): void
{
$timer = new Timer();
- $returnValue = $timer->record('longjohn', static function () {
+ $returnValue = $timer->record('longjohn', static function (): string {
usleep(100000);
return 'test';
diff --git a/tests/system/Events/EventsTest.php b/tests/system/Events/EventsTest.php
index e761c7dff958..db975aaa1825 100644
--- a/tests/system/Events/EventsTest.php
+++ b/tests/system/Events/EventsTest.php
@@ -121,7 +121,7 @@ public function testCancelEvent(): void
// This should cancel the flow of events, and leave
// $result = 1.
- Events::on('foo', static function ($arg) use (&$result) {
+ Events::on('foo', static function ($arg) use (&$result): bool {
$result = 1;
return false;
@@ -138,14 +138,14 @@ public function testPriority(): void
{
$result = 0;
- Events::on('foo', static function () use (&$result) {
+ Events::on('foo', static function () use (&$result): bool {
$result = 1;
return false;
}, EVENT_PRIORITY_NORMAL);
// Since this has a higher priority, it will
// run first.
- Events::on('foo', static function () use (&$result) {
+ Events::on('foo', static function () use (&$result): bool {
$result = 2;
return false;
diff --git a/tests/system/Helpers/URLHelper/MiscUrlTest.php b/tests/system/Helpers/URLHelper/MiscUrlTest.php
index 7b3b6483069d..560729f55c95 100644
--- a/tests/system/Helpers/URLHelper/MiscUrlTest.php
+++ b/tests/system/Helpers/URLHelper/MiscUrlTest.php
@@ -523,7 +523,7 @@ public static function provideAutoLinkUrl(): iterable
],
'test06' => [
'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
- 'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
+ 'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
],
'test07' => [
'Visit example.com or email foo@bar.com',
@@ -623,7 +623,7 @@ public static function provideAutolinkBoth(): iterable
],
'test06' => [
'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
- 'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
+ 'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
],
'test07' => [
'Visit example.com or email foo@bar.com',
@@ -675,7 +675,7 @@ public static function provideAutoLinkPopup(): iterable
],
'test06' => [
'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
- 'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
+ 'This one: ://codeigniter.com must not break this one: http://codeigniter.com',
],
'test07' => [
'Visit example.com or email foo@bar.com',
diff --git a/tests/system/Test/FeatureTestTraitTest.php b/tests/system/Test/FeatureTestTraitTest.php
index b3ee3eadb4cc..a544620d1acd 100644
--- a/tests/system/Test/FeatureTestTraitTest.php
+++ b/tests/system/Test/FeatureTestTraitTest.php
@@ -153,7 +153,7 @@ public function testCallValidationTwice(): void
[
'POST',
'section/create',
- static function () {
+ static function (): string {
$validation = Services::validation();
$validation->setRule('title', 'title', 'required|min_length[3]');
diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php
index 4e16fc2a713f..63db994d6cd1 100644
--- a/tests/system/Validation/ValidationTest.php
+++ b/tests/system/Validation/ValidationTest.php
@@ -311,7 +311,7 @@ public function testClosureRuleWithParamError(): void
$this->validation->setRules([
'foo' => [
'required',
- static function ($value, $data, &$error, $field) {
+ static function ($value, $data, &$error, $field): bool {
if ($value !== 'abc') {
$error = 'The ' . $field . ' value is not "abc"';
diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php
index 0cce9f722ebf..9a9f1fd8d0ac 100644
--- a/tests/system/View/ParserTest.php
+++ b/tests/system/View/ParserTest.php
@@ -806,7 +806,7 @@ public function testParserPluginClosure(): void
public function testParserPluginParams(): void
{
- $this->parser->addPlugin('growth', static function ($str, array $params) {
+ $this->parser->addPlugin('growth', static function ($str, array $params): string {
$step = $params['step'] ?? 1;
$count = $params['count'] ?? 2;
@@ -853,7 +853,7 @@ public function testParserSingleTagWithSingleParams(): void
public function testParserSingleTagWithQuotedParams(): void
{
- $this->parser->addPlugin('count', static function (array $params = []) {
+ $this->parser->addPlugin('count', static function (array $params = []): string {
$out = '';
foreach ($params as $index => $param) {
@@ -870,7 +870,7 @@ public function testParserSingleTagWithQuotedParams(): void
public function testParserSingleTagWithNamedParams(): void
{
- $this->parser->addPlugin('read_params', static function (array $params = []) {
+ $this->parser->addPlugin('read_params', static function (array $params = []): string {
$out = '';
foreach ($params as $index => $param) {
diff --git a/user_guide_src/source/general/ajax.rst b/user_guide_src/source/general/ajax.rst
index 967e2c280c59..ddc276fdf39a 100644
--- a/user_guide_src/source/general/ajax.rst
+++ b/user_guide_src/source/general/ajax.rst
@@ -56,7 +56,7 @@ React
htmx
====
-You can use `ajax-header `_ extension.
+You can use `ajax-header `_ extension.
.. code-block:: html