Skip to content

Commit 77cbf2c

Browse files
authored
Merge pull request #8354 from kenjis/rector-upgrade-php81-CI45
refactor: upgrade to PHP 8.1 with rector
2 parents d01b3a6 + aaa37ad commit 77cbf2c

File tree

149 files changed

+600
-898
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+600
-898
lines changed

app/Views/errors/cli/error_exception.php

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use CodeIgniter\CLI\CLI;
44

55
// The main Exception
6-
CLI::write('[' . get_class($exception) . ']', 'light_gray', 'red');
6+
CLI::write('[' . $exception::class . ']', 'light_gray', 'red');
77
CLI::write($message);
88
CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green'));
99
CLI::newLine();
@@ -14,7 +14,7 @@
1414
$last = $prevException;
1515

1616
CLI::write(' Caused by:');
17-
CLI::write(' [' . get_class($prevException) . ']', 'red');
17+
CLI::write(' [' . $prevException::class . ']', 'red');
1818
CLI::write(' ' . $prevException->getMessage());
1919
CLI::write(' at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green'));
2020
CLI::newLine();
@@ -50,20 +50,11 @@
5050
$function .= $padClass . $error['function'];
5151
}
5252

53-
$args = implode(', ', array_map(static function ($value) {
54-
switch (true) {
55-
case is_object($value):
56-
return 'Object(' . get_class($value) . ')';
57-
58-
case is_array($value):
59-
return count($value) ? '[...]' : '[]';
60-
61-
case $value === null:
62-
return 'null'; // return the lowercased version
63-
64-
default:
65-
return var_export($value, true);
66-
}
53+
$args = implode(', ', array_map(static fn ($value) => match (true) {
54+
is_object($value) => 'Object(' . $value::class . ')',
55+
is_array($value) => count($value) ? '[...]' : '[]',
56+
$value === null => 'null', // return the lowercased version
57+
default => var_export($value, true),
6758
}, array_values($error['args'] ?? [])));
6859

6960
$function .= '(' . $args . ')';

app/Views/errors/html/error_exception.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@
6161

6262
<pre>
6363
Caused by:
64-
<?= esc(get_class($prevException)), esc($prevException->getCode() ? ' #' . $prevException->getCode() : '') ?>
64+
<?= esc($prevException::class), esc($prevException->getCode() ? ' #' . $prevException->getCode() : '') ?>
6565

6666
<?= nl2br(esc($prevException->getMessage())) ?>
67-
<a href="https://www.duckduckgo.com/?q=<?= urlencode(get_class($prevException) . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $prevException->getMessage())) ?>"
67+
<a href="https://www.duckduckgo.com/?q=<?= urlencode($prevException::class . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $prevException->getMessage())) ?>"
6868
rel="noreferrer" target="_blank">search &rarr;</a>
6969
<?= esc(clean_path($prevException->getFile()) . ':' . $prevException->getLine()) ?>
7070
</pre>
@@ -121,7 +121,7 @@
121121
<?php
122122
$params = null;
123123
// Reflection by name is not available for closure function
124-
if (substr($row['function'], -1) !== '}') {
124+
if (! str_ends_with($row['function'], '}')) {
125125
$mirror = isset($row['class']) ? new ReflectionMethod($row['class'], $row['function']) : new ReflectionFunction($row['function']);
126126
$params = $mirror->getParameters();
127127
}

phpstan-baseline.php

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,11 +1341,6 @@
13411341
'count' => 1,
13421342
'path' => __DIR__ . '/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php',
13431343
];
1344-
$ignoreErrors[] = [
1345-
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\Routes\\\\AutoRouterImproved\\\\AutoRouteCollector\\:\\:__construct\\(\\) has parameter \\$protectedControllers with no value type specified in iterable type array\\.$#',
1346-
'count' => 1,
1347-
'path' => __DIR__ . '/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php',
1348-
];
13491344
$ignoreErrors[] = [
13501345
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\Routes\\\\AutoRouterImproved\\\\AutoRouteCollector\\:\\:addFilters\\(\\) has no return type specified\\.$#',
13511346
'count' => 1,
@@ -1361,16 +1356,6 @@
13611356
'count' => 1,
13621357
'path' => __DIR__ . '/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php',
13631358
];
1364-
$ignoreErrors[] = [
1365-
'message' => '#^Property CodeIgniter\\\\Commands\\\\Utilities\\\\Routes\\\\AutoRouterImproved\\\\AutoRouteCollector\\:\\:\\$httpMethods type has no value type specified in iterable type array\\.$#',
1366-
'count' => 1,
1367-
'path' => __DIR__ . '/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php',
1368-
];
1369-
$ignoreErrors[] = [
1370-
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\Routes\\\\AutoRouterImproved\\\\ControllerMethodReader\\:\\:__construct\\(\\) has parameter \\$httpMethods with no value type specified in iterable type array\\.$#',
1371-
'count' => 1,
1372-
'path' => __DIR__ . '/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php',
1373-
];
13741359
$ignoreErrors[] = [
13751360
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\Routes\\\\AutoRouterImproved\\\\ControllerMethodReader\\:\\:getParameters\\(\\) return type has no value type specified in iterable type array\\.$#',
13761361
'count' => 1,
@@ -7561,11 +7546,6 @@
75617546
'count' => 1,
75627547
'path' => __DIR__ . '/system/RESTful/ResourceController.php',
75637548
];
7564-
$ignoreErrors[] = [
7565-
'message' => '#^Method CodeIgniter\\\\Router\\\\AutoRouter\\:\\:__construct\\(\\) has parameter \\$cliRoutes with no value type specified in iterable type array\\.$#',
7566-
'count' => 1,
7567-
'path' => __DIR__ . '/system/Router/AutoRouter.php',
7568-
];
75697549
$ignoreErrors[] = [
75707550
'message' => '#^Method CodeIgniter\\\\Router\\\\AutoRouter\\:\\:getRoute\\(\\) return type has no value type specified in iterable type array\\.$#',
75717551
'count' => 1,
@@ -11841,11 +11821,6 @@
1184111821
'count' => 1,
1184211822
'path' => __DIR__ . '/tests/system/CommonSingleServiceTest.php',
1184311823
];
11844-
$ignoreErrors[] = [
11845-
'message' => '#^Parameter \\#1 \\$expected of method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) expects class\\-string\\<object\\>, false given\\.$#',
11846-
'count' => 2,
11847-
'path' => __DIR__ . '/tests/system/CommonSingleServiceTest.php',
11848-
];
1184911824
$ignoreErrors[] = [
1185011825
'message' => '#^Accessing offset \'BAR\' directly on \\$_SERVER is discouraged\\.$#',
1185111826
'count' => 1,

rector.php

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
use Rector\Php70\Rector\FuncCall\RandomFunctionRector;
4747
use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector;
4848
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
49+
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
50+
use Rector\Php80\Rector\FunctionLike\MixedTypeRector;
51+
use Rector\Php81\Rector\ClassConst\FinalizePublicClassConstantRector;
52+
use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector;
4953
use Rector\PHPUnit\AnnotationsToAttributes\Rector\Class_\AnnotationWithValueToAttributeRector;
5054
use Rector\PHPUnit\AnnotationsToAttributes\Rector\Class_\CoversAnnotationWithValueToAttributeRector;
5155
use Rector\PHPUnit\AnnotationsToAttributes\Rector\ClassMethod\DataProviderAnnotationToAttributeRector;
@@ -57,6 +61,7 @@
5761
use Rector\Set\ValueObject\SetList;
5862
use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector;
5963
use Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector;
64+
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
6065
use Rector\TypeDeclaration\Rector\Empty_\EmptyOnNullableObjectToInstanceOfRector;
6166
use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector;
6267
use Utils\Rector\PassStrictParameterToFunctionParameterRector;
@@ -66,7 +71,7 @@
6671
return static function (RectorConfig $rectorConfig): void {
6772
$rectorConfig->sets([
6873
SetList::DEAD_CODE,
69-
LevelSetList::UP_TO_PHP_74,
74+
LevelSetList::UP_TO_PHP_81,
7075
PHPUnitSetList::PHPUNIT_CODE_QUALITY,
7176
PHPUnitSetList::PHPUNIT_100,
7277
]);
@@ -155,6 +160,49 @@
155160

156161
SimplifyRegexPatternRector::class,
157162

163+
// PHP 8.0 features but cause breaking changes
164+
ClassPropertyAssignToConstructorPromotionRector::class => [
165+
__DIR__ . '/system/Database/BaseResult.php',
166+
__DIR__ . '/system/Database/RawSql.php',
167+
__DIR__ . '/system/Debug/BaseExceptionHandler.php',
168+
__DIR__ . '/system/Filters/Filters.php',
169+
__DIR__ . '/system/HTTP/CURLRequest.php',
170+
__DIR__ . '/system/HTTP/DownloadResponse.php',
171+
__DIR__ . '/system/HTTP/IncomingRequest.php',
172+
__DIR__ . '/system/Security/Security.php',
173+
__DIR__ . '/system/Session/Session.php',
174+
],
175+
MixedTypeRector::class,
176+
177+
// PHP 8.1 features but cause breaking changes
178+
FinalizePublicClassConstantRector::class => [
179+
__DIR__ . '/system/Cache/Handlers/BaseHandler.php',
180+
__DIR__ . '/system/Cache/Handlers/FileHandler.php',
181+
__DIR__ . '/system/CodeIgniter.php',
182+
__DIR__ . '/system/Events/Events.php',
183+
__DIR__ . '/system/Log/Handlers/ChromeLoggerHandler.php',
184+
__DIR__ . '/system/Log/Handlers/ErrorlogHandler.php',
185+
__DIR__ . '/system/Security/Security.php',
186+
],
187+
ReturnNeverTypeRector::class => [
188+
__DIR__ . '/system/Cache/Handlers/BaseHandler.php',
189+
__DIR__ . '/system/Cache/Handlers/MemcachedHandler.php',
190+
__DIR__ . '/system/Cache/Handlers/WincacheHandler.php',
191+
__DIR__ . '/system/CodeIgniter.php',
192+
__DIR__ . '/system/Database/MySQLi/Utils.php',
193+
__DIR__ . '/system/Database/OCI8/Utils.php',
194+
__DIR__ . '/system/Database/Postgre/Utils.php',
195+
__DIR__ . '/system/Database/SQLSRV/Utils.php',
196+
__DIR__ . '/system/Database/SQLite3/Utils.php',
197+
__DIR__ . '/system/HTTP/DownloadResponse.php',
198+
__DIR__ . '/system/HTTP/SiteURI.php',
199+
__DIR__ . '/system/Helpers/kint_helper.php',
200+
__DIR__ . '/tests/_support/Autoloader/FatalLocator.php',
201+
],
202+
203+
// Unnecessary (string) is inserted
204+
NullToStrictStringFuncCallArgRector::class,
205+
158206
// PHPUnit 10 (requires PHP 8.1) features
159207
DataProviderAnnotationToAttributeRector::class,
160208
DependsAnnotationWithValueToAttributeRector::class,

system/Autoloader/Autoloader.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,10 @@ private function loadComposerAutoloader(Modules $modules): void
163163
public function register()
164164
{
165165
// Register classmap loader for the files in our class map.
166-
spl_autoload_register([$this, 'loadClassmap'], true);
166+
spl_autoload_register($this->loadClassmap(...), true);
167167

168168
// Register the PSR-4 autoloader.
169-
spl_autoload_register([$this, 'loadClass'], true);
169+
spl_autoload_register($this->loadClass(...), true);
170170

171171
// Load our non-class files
172172
foreach ($this->files as $file) {
@@ -181,8 +181,8 @@ public function register()
181181
*/
182182
public function unregister(): void
183183
{
184-
spl_autoload_unregister([$this, 'loadClass']);
185-
spl_autoload_unregister([$this, 'loadClassmap']);
184+
spl_autoload_unregister($this->loadClass(...));
185+
spl_autoload_unregister($this->loadClassmap(...));
186186
}
187187

188188
/**
@@ -281,12 +281,12 @@ public function loadClass(string $class): void
281281
*/
282282
protected function loadInNamespace(string $class)
283283
{
284-
if (strpos($class, '\\') === false) {
284+
if (! str_contains($class, '\\')) {
285285
return false;
286286
}
287287

288288
foreach ($this->prefixes as $namespace => $directories) {
289-
if (strpos($class, $namespace) === 0) {
289+
if (str_starts_with($class, $namespace)) {
290290
$relativeClassPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, strlen($namespace)));
291291

292292
foreach ($directories as $directory) {
@@ -425,7 +425,7 @@ private function loadComposerNamespaces(ClassLoader $composer, array $composerPa
425425

426426
foreach ($srcPaths as $path) {
427427
foreach ($installPaths as $installPath) {
428-
if ($installPath === substr($path, 0, strlen($installPath))) {
428+
if (str_starts_with($path, $installPath)) {
429429
$add = true;
430430
break 2;
431431
}

system/Autoloader/FileLocator.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ public function locateFile(string $file, ?string $folder = null, string $ext = '
5353
$file = $this->ensureExt($file, $ext);
5454

5555
// Clears the folder name if it is at the beginning of the filename
56-
if ($folder !== null && strpos($file, $folder) === 0) {
56+
if ($folder !== null && str_starts_with($file, $folder)) {
5757
$file = substr($file, strlen($folder . '/'));
5858
}
5959

6060
// Is not namespaced? Try the application folder.
61-
if (strpos($file, '\\') === false) {
61+
if (! str_contains($file, '\\')) {
6262
return $this->legacyLocate($file, $folder);
6363
}
6464

@@ -103,7 +103,7 @@ public function locateFile(string $file, ?string $folder = null, string $ext = '
103103
// If we have a folder name, then the calling function
104104
// expects this file to be within that folder, like 'Views',
105105
// or 'libraries'.
106-
if ($folder !== null && strpos($path . $filename, '/' . $folder . '/') === false) {
106+
if ($folder !== null && ! str_contains($path . $filename, '/' . $folder . '/')) {
107107
$path .= trim($folder, '/') . '/';
108108
}
109109

@@ -192,7 +192,7 @@ public function search(string $path, string $ext = 'php', bool $prioritizeApp =
192192

193193
if ($prioritizeApp) {
194194
$foundPaths[] = $fullPath;
195-
} elseif (strpos($fullPath, APPPATH) === 0) {
195+
} elseif (str_starts_with($fullPath, APPPATH)) {
196196
$appPaths[] = $fullPath;
197197
} else {
198198
$foundPaths[] = $fullPath;
@@ -216,7 +216,7 @@ protected function ensureExt(string $path, string $ext): string
216216
if ($ext !== '') {
217217
$ext = '.' . $ext;
218218

219-
if (substr($path, -strlen($ext)) !== $ext) {
219+
if (! str_ends_with($path, $ext)) {
220220
$path .= $ext;
221221
}
222222
}

system/Autoloader/FileLocatorCached.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
*/
2424
final class FileLocatorCached implements FileLocatorInterface
2525
{
26-
private FileLocator $locator;
27-
2826
/**
2927
* @var CacheInterface|FileVarExportHandler
3028
*/
@@ -51,10 +49,9 @@ final class FileLocatorCached implements FileLocatorInterface
5149
/**
5250
* @param CacheInterface|FileVarExportHandler|null $cache
5351
*/
54-
public function __construct(FileLocator $locator, $cache = null)
52+
public function __construct(private readonly FileLocator $locator, $cache = null)
5553
{
5654
$this->cacheHandler = $cache ?? new FileVarExportHandler();
57-
$this->locator = $locator;
5855

5956
$this->loadCache();
6057
}

system/BaseModel.php

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ public function find($id = null)
634634
*/
635635
public function findColumn(string $columnName)
636636
{
637-
if (strpos($columnName, ',') !== false) {
637+
if (str_contains($columnName, ',')) {
638638
throw DataException::forFindColumnHaveMultipleColumns();
639639
}
640640

@@ -1397,19 +1397,12 @@ protected function setDate(?int $userData = null)
13971397
*/
13981398
protected function intToDate(int $value)
13991399
{
1400-
switch ($this->dateFormat) {
1401-
case 'int':
1402-
return $value;
1403-
1404-
case 'datetime':
1405-
return date($this->db->dateFormat['datetime'], $value);
1406-
1407-
case 'date':
1408-
return date($this->db->dateFormat['date'], $value);
1409-
1410-
default:
1411-
throw ModelException::forNoDateFormat(static::class);
1412-
}
1400+
return match ($this->dateFormat) {
1401+
'int' => $value,
1402+
'datetime' => date($this->db->dateFormat['datetime'], $value),
1403+
'date' => date($this->db->dateFormat['date'], $value),
1404+
default => throw ModelException::forNoDateFormat(static::class),
1405+
};
14131406
}
14141407

14151408
/**
@@ -1426,19 +1419,12 @@ protected function intToDate(int $value)
14261419
*/
14271420
protected function timeToDate(Time $value)
14281421
{
1429-
switch ($this->dateFormat) {
1430-
case 'datetime':
1431-
return $value->format($this->db->dateFormat['datetime']);
1432-
1433-
case 'date':
1434-
return $value->format($this->db->dateFormat['date']);
1435-
1436-
case 'int':
1437-
return $value->getTimestamp();
1438-
1439-
default:
1440-
return (string) $value;
1441-
}
1422+
return match ($this->dateFormat) {
1423+
'datetime' => $value->format($this->db->dateFormat['datetime']),
1424+
'date' => $value->format($this->db->dateFormat['date']),
1425+
'int' => $value->getTimestamp(),
1426+
default => (string) $value,
1427+
};
14421428
}
14431429

14441430
/**

system/CLI/CLI.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ public static function color(string $text, string $foreground, ?string $backgrou
592592
$newText = '';
593593

594594
// Detect if color method was already in use with this text
595-
if (strpos($text, "\033[0m") !== false) {
595+
if (str_contains($text, "\033[0m")) {
596596
$pattern = '/\\033\\[0;.+?\\033\\[0m/u';
597597

598598
preg_match_all($pattern, $text, $matches);

system/CLI/Commands.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ protected function getCommandAlternatives(string $name, array $collection): arra
183183
foreach (array_keys($collection) as $commandName) {
184184
$lev = levenshtein($name, $commandName);
185185

186-
if ($lev <= strlen($commandName) / 3 || strpos($commandName, $name) !== false) {
186+
if ($lev <= strlen($commandName) / 3 || str_contains($commandName, $name)) {
187187
$alternatives[$commandName] = $lev;
188188
}
189189
}

system/CLI/GeneratorTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ protected function qualifyClassName(): string
268268
// Gets the namespace from input. Don't forget the ending backslash!
269269
$namespace = $this->getNamespace() . '\\';
270270

271-
if (strncmp($class, $namespace, strlen($namespace)) === 0) {
271+
if (str_starts_with($class, $namespace)) {
272272
return $class; // @codeCoverageIgnore
273273
}
274274

0 commit comments

Comments
 (0)