diff --git a/app/Views/errors/cli/error_exception.php b/app/Views/errors/cli/error_exception.php index 98d83b0ed3a6..e908b426381d 100644 --- a/app/Views/errors/cli/error_exception.php +++ b/app/Views/errors/cli/error_exception.php @@ -3,7 +3,7 @@ use CodeIgniter\CLI\CLI; // The main Exception -CLI::write('[' . get_class($exception) . ']', 'light_gray', 'red'); +CLI::write('[' . $exception::class . ']', 'light_gray', 'red'); CLI::write($message); CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green')); CLI::newLine(); @@ -14,7 +14,7 @@ $last = $prevException; CLI::write(' Caused by:'); - CLI::write(' [' . get_class($prevException) . ']', 'red'); + CLI::write(' [' . $prevException::class . ']', 'red'); CLI::write(' ' . $prevException->getMessage()); CLI::write(' at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green')); CLI::newLine(); @@ -50,20 +50,11 @@ $function .= $padClass . $error['function']; } - $args = implode(', ', array_map(static function ($value) { - switch (true) { - case is_object($value): - return 'Object(' . get_class($value) . ')'; - - case is_array($value): - return count($value) ? '[...]' : '[]'; - - case $value === null: - return 'null'; // return the lowercased version - - default: - return var_export($value, true); - } + $args = implode(', ', array_map(static fn ($value) => match (true) { + is_object($value) => 'Object(' . $value::class . ')', + is_array($value) => count($value) ? '[...]' : '[]', + $value === null => 'null', + default => var_export($value, true), }, array_values($error['args'] ?? []))); $function .= '(' . $args . ')'; diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 29a08d19caa8..7f4717d4f291 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -55,10 +55,10 @@
     Caused by:
-    getCode() ? ' #' . $prevException->getCode() : '') ?>
+    getCode() ? ' #' . $prevException->getCode() : '') ?>
 
     getMessage())) ?>
-    getMessage())) ?>"
+    getMessage())) ?>"
        rel="noreferrer" target="_blank">search →
     getFile()) . ':' . $prevException->getLine()) ?>
     
@@ -115,7 +115,7 @@ getParameters(); } diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 979935aa8e2d..3a5500a4ce28 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -2641,11 +2641,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Router/AutoRouter.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\Router\\\\AutoRouter\\:\\:\\$cliRoutes type has no signature specified for Closure\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Router/AutoRouter.php', -]; $ignoreErrors[] = [ 'message' => '#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#', 'count' => 1, diff --git a/rector.php b/rector.php index 1eaacd12328b..bc6b54cf2883 100644 --- a/rector.php +++ b/rector.php @@ -37,12 +37,22 @@ use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Php70\Rector\FuncCall\RandomFunctionRector; use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector; +use Rector\Php80\Rector\Class_\AnnotationToAttributeRector; +use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; +use Rector\Php80\Rector\FunctionLike\MixedTypeRector; +use Rector\Php81\Rector\ClassConst\FinalizePublicClassConstantRector; +use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector; +use Rector\PHPUnit\AnnotationsToAttributes\Rector\Class_\AnnotationWithValueToAttributeRector; +use Rector\PHPUnit\AnnotationsToAttributes\Rector\Class_\CoversAnnotationWithValueToAttributeRector; +use Rector\PHPUnit\AnnotationsToAttributes\Rector\ClassMethod\DataProviderAnnotationToAttributeRector; +use Rector\PHPUnit\AnnotationsToAttributes\Rector\ClassMethod\DependsAnnotationWithValueToAttributeRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; use Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector; +use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector; use Utils\Rector\PassStrictParameterToFunctionParameterRector; use Utils\Rector\RemoveErrorSuppressInTryCatchStmtsRector; use Utils\Rector\UnderscoreToCamelCaseVariableNameRector; @@ -50,7 +60,7 @@ return static function (RectorConfig $rectorConfig): void { $rectorConfig->sets([ SetList::DEAD_CODE, - LevelSetList::UP_TO_PHP_74, + LevelSetList::UP_TO_PHP_81, PHPUnitSetList::PHPUNIT_CODE_QUALITY, PHPUnitSetList::PHPUNIT_100, ]); @@ -78,6 +88,7 @@ __DIR__ . '/tests/system/Config/fixtures', __DIR__ . '/tests/system/Filters/fixtures', __DIR__ . '/tests/_support', + JsonThrowOnErrorRector::class, YieldDataProviderRector::class, @@ -110,6 +121,54 @@ RandomFunctionRector::class, SimplifyRegexPatternRector::class, + + // PHP 8.0 features but cause breaking changes + ClassPropertyAssignToConstructorPromotionRector::class => [ + __DIR__ . '/system/Database/BaseResult.php', + __DIR__ . '/system/Database/RawSql.php', + __DIR__ . '/system/Debug/BaseExceptionHandler.php', + __DIR__ . '/system/Filters/Filters.php', + __DIR__ . '/system/HTTP/CURLRequest.php', + __DIR__ . '/system/HTTP/DownloadResponse.php', + __DIR__ . '/system/HTTP/IncomingRequest.php', + __DIR__ . '/system/Security/Security.php', + __DIR__ . '/system/Session/Session.php', + ], + MixedTypeRector::class, + + // PHP 8.1 features but cause breaking changes + FinalizePublicClassConstantRector::class => [ + __DIR__ . '/system/Cache/Handlers/BaseHandler.php', + __DIR__ . '/system/Cache/Handlers/FileHandler.php', + __DIR__ . '/system/CodeIgniter.php', + __DIR__ . '/system/Events/Events.php', + __DIR__ . '/system/Log/Handlers/ChromeLoggerHandler.php', + __DIR__ . '/system/Log/Handlers/ErrorlogHandler.php', + __DIR__ . '/system/Security/Security.php', + ], + ReturnNeverTypeRector::class => [ + __DIR__ . '/system/Cache/Handlers/MemcachedHandler.php', + __DIR__ . '/system/Cache/Handlers/WincacheHandler.php', + __DIR__ . '/system/CodeIgniter.php', + __DIR__ . '/system/Database/MySQLi/Utils.php', + __DIR__ . '/system/Database/OCI8/Utils.php', + __DIR__ . '/system/Database/Postgre/Utils.php', + __DIR__ . '/system/Database/SQLSRV/Utils.php', + __DIR__ . '/system/Database/SQLite3/Utils.php', + __DIR__ . '/system/HTTP/DownloadResponse.php', + __DIR__ . '/system/HTTP/SiteURI.php', + __DIR__ . '/system/Helpers/kint_helper.php', + ], + + // Unnecessary (string) is inserted + NullToStrictStringFuncCallArgRector::class, + + // PHPUnit 10 (requires PHP 8.1) features + DataProviderAnnotationToAttributeRector::class, + DependsAnnotationWithValueToAttributeRector::class, + AnnotationWithValueToAttributeRector::class, + AnnotationToAttributeRector::class, + CoversAnnotationWithValueToAttributeRector::class, ]); // auto import fully qualified class names diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 020dd5b1a4f2..b8b235680532 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -156,10 +156,10 @@ private function loadComposerAutoloader(Modules $modules): void public function register() { // Register classmap loader for the files in our class map. - spl_autoload_register([$this, 'loadClassmap'], true); + spl_autoload_register($this->loadClassmap(...), true); // Register the PSR-4 autoloader. - spl_autoload_register([$this, 'loadClass'], true); + spl_autoload_register($this->loadClass(...), true); // Load our non-class files foreach ($this->files as $file) { @@ -174,8 +174,8 @@ public function register() */ public function unregister(): void { - spl_autoload_unregister([$this, 'loadClass']); - spl_autoload_unregister([$this, 'loadClassmap']); + spl_autoload_unregister($this->loadClass(...)); + spl_autoload_unregister($this->loadClassmap(...)); } /** @@ -273,7 +273,7 @@ public function loadClass(string $class): void */ protected function loadInNamespace(string $class) { - if (strpos($class, '\\') === false) { + if (! str_contains($class, '\\')) { return false; } @@ -281,7 +281,7 @@ protected function loadInNamespace(string $class) foreach ($directories as $directory) { $directory = rtrim($directory, '\\/'); - if (strpos($class, $namespace) === 0) { + if (str_starts_with($class, $namespace)) { $filePath = $directory . str_replace('\\', DIRECTORY_SEPARATOR, substr($class, strlen($namespace))) . '.php'; $filename = $this->includeFile($filePath); @@ -415,7 +415,7 @@ private function loadComposerNamespaces(ClassLoader $composer, array $composerPa foreach ($srcPaths as $path) { foreach ($installPaths as $installPath) { - if ($installPath === substr($path, 0, strlen($installPath))) { + if (str_starts_with($path, $installPath)) { $add = true; break 2; } @@ -465,7 +465,7 @@ protected function discoverComposerNamespaces() $newPaths[rtrim($key, '\\ ')] = $value; } - $this->prefixes = array_merge($this->prefixes, $newPaths); + $this->prefixes = [...$this->prefixes, ...$newPaths]; $this->classmap = array_merge($this->classmap, $classes); } diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index e3821c1df27e..2484eda0860f 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -51,12 +51,12 @@ public function locateFile(string $file, ?string $folder = null, string $ext = ' $file = $this->ensureExt($file, $ext); // Clears the folder name if it is at the beginning of the filename - if (! empty($folder) && strpos($file, $folder) === 0) { + if (! empty($folder) && str_starts_with($file, $folder)) { $file = substr($file, strlen($folder . '/')); } // Is not namespaced? Try the application folder. - if (strpos($file, '\\') === false) { + if (! str_contains($file, '\\')) { return $this->legacyLocate($file, $folder); } @@ -101,7 +101,7 @@ public function locateFile(string $file, ?string $folder = null, string $ext = ' // If we have a folder name, then the calling function // expects this file to be within that folder, like 'Views', // or 'libraries'. - if (! empty($folder) && strpos($path . $filename, '/' . $folder . '/') === false) { + if (! empty($folder) && ! str_contains($path . $filename, '/' . $folder . '/')) { $path .= trim($folder, '/') . '/'; } @@ -188,7 +188,7 @@ public function search(string $path, string $ext = 'php', bool $prioritizeApp = if ($prioritizeApp) { $foundPaths[] = $fullPath; - } elseif (strpos($fullPath, APPPATH) === 0) { + } elseif (str_starts_with($fullPath, APPPATH)) { $appPaths[] = $fullPath; } else { $foundPaths[] = $fullPath; @@ -212,7 +212,7 @@ protected function ensureExt(string $path, string $ext): string if ($ext !== '') { $ext = '.' . $ext; - if (substr($path, -strlen($ext)) !== $ext) { + if (! str_ends_with($path, $ext)) { $path .= $ext; } } diff --git a/system/Autoloader/FileLocatorCached.php b/system/Autoloader/FileLocatorCached.php index 8bc8d1e85ee9..2dfe85a38f0b 100644 --- a/system/Autoloader/FileLocatorCached.php +++ b/system/Autoloader/FileLocatorCached.php @@ -21,8 +21,6 @@ */ final class FileLocatorCached implements FileLocatorInterface { - private FileLocator $locator; - /** * @var CacheInterface|FileVarExportHandler */ @@ -49,10 +47,11 @@ final class FileLocatorCached implements FileLocatorInterface /** * @param CacheInterface|FileVarExportHandler|null $cache */ - public function __construct(FileLocator $locator, $cache = null) - { + public function __construct( + private readonly FileLocator $locator, + $cache = null + ) { $this->cacheHandler = $cache ?? new FileVarExportHandler(); - $this->locator = $locator; $this->loadCache(); } diff --git a/system/BaseModel.php b/system/BaseModel.php index 7afdf9c1cb4d..14b2680875f7 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -577,7 +577,7 @@ public function find($id = null) */ public function findColumn(string $columnName) { - if (strpos($columnName, ',') !== false) { + if (str_contains($columnName, ',')) { throw DataException::forFindColumnHaveMultipleColumns(); } @@ -1313,19 +1313,12 @@ protected function setDate(?int $userData = null) */ protected function intToDate(int $value) { - switch ($this->dateFormat) { - case 'int': - return $value; - - case 'datetime': - return date('Y-m-d H:i:s', $value); - - case 'date': - return date('Y-m-d', $value); - - default: - throw ModelException::forNoDateFormat(static::class); - } + return match ($this->dateFormat) { + 'int' => $value, + 'datetime' => date('Y-m-d H:i:s', $value), + 'date' => date('Y-m-d', $value), + default => throw ModelException::forNoDateFormat(static::class), + }; } /** @@ -1342,19 +1335,12 @@ protected function intToDate(int $value) */ protected function timeToDate(Time $value) { - switch ($this->dateFormat) { - case 'datetime': - return $value->format('Y-m-d H:i:s'); - - case 'date': - return $value->format('Y-m-d'); - - case 'int': - return $value->getTimestamp(); - - default: - return (string) $value; - } + return match ($this->dateFormat) { + 'datetime' => $value->format('Y-m-d H:i:s'), + 'date' => $value->format('Y-m-d'), + 'int' => $value->getTimestamp(), + default => (string) $value, + }; } /** diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index e2aa363e5851..23d5f05a2b4c 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -590,7 +590,7 @@ public static function color(string $text, string $foreground, ?string $backgrou $newText = ''; // Detect if color method was already in use with this text - if (strpos($text, "\033[0m") !== false) { + if (str_contains($text, "\033[0m")) { $pattern = '/\\033\\[0;.+?\\033\\[0m/u'; preg_match_all($pattern, $text, $matches); diff --git a/system/CLI/Commands.php b/system/CLI/Commands.php index 7cb5351cf3b5..0c9bcabae37d 100644 --- a/system/CLI/Commands.php +++ b/system/CLI/Commands.php @@ -174,7 +174,7 @@ protected function getCommandAlternatives(string $name, array $collection): arra foreach (array_keys($collection) as $commandName) { $lev = levenshtein($name, $commandName); - if ($lev <= strlen($commandName) / 3 || strpos($commandName, $name) !== false) { + if ($lev <= strlen($commandName) / 3 || str_contains($commandName, $name)) { $alternatives[$commandName] = $lev; } } diff --git a/system/CLI/Console.php b/system/CLI/Console.php index adcf9aaeca8b..3e7b8a767a82 100644 --- a/system/CLI/Console.php +++ b/system/CLI/Console.php @@ -39,7 +39,7 @@ public function run() Services::routes()->loadRoutes(); $runner = Services::commands(); - $params = array_merge(CLI::getSegments(), CLI::getOptions()); + $params = [...CLI::getSegments(), ...CLI::getOptions()]; $params = $this->parseParamsForHelpOption($params); $command = array_shift($params) ?? 'list'; diff --git a/system/CLI/GeneratorTrait.php b/system/CLI/GeneratorTrait.php index c1112ca63481..c2260b4abb71 100644 --- a/system/CLI/GeneratorTrait.php +++ b/system/CLI/GeneratorTrait.php @@ -309,7 +309,7 @@ protected function qualifyClassName(): string '\\' ) . '\\'; - if (strncmp($class, $namespace, strlen($namespace)) === 0) { + if (str_starts_with($class, $namespace)) { return $class; // @codeCoverageIgnore } diff --git a/system/CLI/InputOutput.php b/system/CLI/InputOutput.php index 5b6c1da02f4d..b69c19e2eee1 100644 --- a/system/CLI/InputOutput.php +++ b/system/CLI/InputOutput.php @@ -21,7 +21,7 @@ class InputOutput /** * Is the readline library on the system? */ - private bool $readlineSupport; + private readonly bool $readlineSupport; public function __construct() { diff --git a/system/Cache/Handlers/MemcachedHandler.php b/system/Cache/Handlers/MemcachedHandler.php index e8658906392a..c89ecd10e595 100644 --- a/system/Cache/Handlers/MemcachedHandler.php +++ b/system/Cache/Handlers/MemcachedHandler.php @@ -51,7 +51,7 @@ public function __construct(Cache $config) { $this->prefix = $config->prefix; - $this->config = array_merge($this->config, $config->memcached); + $this->config = [...$this->config, ...$config->memcached]; } /** diff --git a/system/Cache/Handlers/PredisHandler.php b/system/Cache/Handlers/PredisHandler.php index 986d083ebc69..ca4e9f9d0465 100644 --- a/system/Cache/Handlers/PredisHandler.php +++ b/system/Cache/Handlers/PredisHandler.php @@ -53,7 +53,7 @@ public function __construct(Cache $config) $this->prefix = $config->prefix; if (isset($config->redis)) { - $this->config = array_merge($this->config, $config->redis); + $this->config = [...$this->config, ...$config->redis]; } } @@ -86,22 +86,15 @@ public function get(string $key) return null; } - switch ($data['__ci_type']) { - case 'array': - case 'object': - return unserialize($data['__ci_value']); - - case 'boolean': - case 'integer': - case 'double': // Yes, 'double' is returned and NOT 'float' - case 'string': - case 'NULL': - return settype($data['__ci_value'], $data['__ci_type']) ? $data['__ci_value'] : null; - - case 'resource': - default: - return null; - } + return match ($data['__ci_type']) { + 'array', 'object' => unserialize($data['__ci_value']), + 'boolean', + 'integer', + 'double', // Yes, 'double' is returned and NOT 'float' + 'string', + 'NULL' => settype($data['__ci_value'], $data['__ci_type']) ? $data['__ci_value'] : null, + default => null, + }; } /** diff --git a/system/Cache/Handlers/RedisHandler.php b/system/Cache/Handlers/RedisHandler.php index 953de2dc20be..d4d6097ff527 100644 --- a/system/Cache/Handlers/RedisHandler.php +++ b/system/Cache/Handlers/RedisHandler.php @@ -51,7 +51,7 @@ public function __construct(Cache $config) { $this->prefix = $config->prefix; - $this->config = array_merge($this->config, $config->redis); + $this->config = [...$this->config, ...$config->redis]; } /** @@ -112,22 +112,15 @@ public function get(string $key) return null; } - switch ($data['__ci_type']) { - case 'array': - case 'object': - return unserialize($data['__ci_value']); - - case 'boolean': - case 'integer': - case 'double': // Yes, 'double' is returned and NOT 'float' - case 'string': - case 'NULL': - return settype($data['__ci_value'], $data['__ci_type']) ? $data['__ci_value'] : null; - - case 'resource': - default: - return null; - } + return match ($data['__ci_type']) { + 'array', 'object' => unserialize($data['__ci_value']), + 'boolean', + 'integer', + 'double', // Yes, 'double' is returned and NOT 'float' + 'string', + 'NULL' => settype($data['__ci_value'], $data['__ci_type']) ? $data['__ci_value'] : null, + default => null, + }; } /** diff --git a/system/Cache/ResponseCache.php b/system/Cache/ResponseCache.php index 6e8e8b4887b1..064b9250b5a6 100644 --- a/system/Cache/ResponseCache.php +++ b/system/Cache/ResponseCache.php @@ -47,12 +47,11 @@ final class ResponseCache */ private int $ttl = 0; - private CacheInterface $cache; - - public function __construct(CacheConfig $config, CacheInterface $cache) - { + public function __construct( + CacheConfig $config, + private readonly CacheInterface $cache + ) { $this->cacheQueryString = $config->cacheQueryString; - $this->cache = $cache; } /** diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 87a2a55b0caa..c508e8afdcde 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -867,7 +867,7 @@ protected function startController() $this->benchmark->start('controller_constructor'); // Is it routed to a Closure? - if (is_object($this->controller) && (get_class($this->controller) === 'Closure')) { + if (is_object($this->controller) && ($this->controller::class === 'Closure')) { $controller = $this->controller; return $controller(...$this->router->params()); @@ -1038,7 +1038,7 @@ public function storePreviousURL($uri) } // Ignore non-HTML responses - if (strpos($this->response->getHeaderLine('Content-Type'), 'text/html') === false) { + if (! str_contains($this->response->getHeaderLine('Content-Type'), 'text/html')) { return; } diff --git a/system/Commands/Database/CreateDatabase.php b/system/Commands/Database/CreateDatabase.php index d103d97f689a..32643320b00f 100644 --- a/system/Commands/Database/CreateDatabase.php +++ b/system/Commands/Database/CreateDatabase.php @@ -107,7 +107,7 @@ public function run(array $params) $config->{$group}['database'] = $name; if ($name !== ':memory:') { - $dbName = strpos($name, DIRECTORY_SEPARATOR) === false ? WRITEPATH . $name : $name; + $dbName = ! str_contains($name, DIRECTORY_SEPARATOR) ? WRITEPATH . $name : $name; if (is_file($dbName)) { CLI::error("Database \"{$dbName}\" already exists.", 'light_gray', 'red'); diff --git a/system/Commands/Encryption/GenerateKey.php b/system/Commands/Encryption/GenerateKey.php index 419ae6ef3e34..c10a76e81e43 100644 --- a/system/Commands/Encryption/GenerateKey.php +++ b/system/Commands/Encryption/GenerateKey.php @@ -166,7 +166,7 @@ protected function writeNewEncryptionKeyToFile(string $oldKey, string $newKey): $oldFileContents = (string) file_get_contents($envFile); $replacementKey = "\nencryption.key = {$newKey}"; - if (strpos($oldFileContents, 'encryption.key') === false) { + if (! str_contains($oldFileContents, 'encryption.key')) { return file_put_contents($envFile, $replacementKey, FILE_APPEND) !== false; } diff --git a/system/Commands/Generators/CellGenerator.php b/system/Commands/Generators/CellGenerator.php index 3d31231697fe..a6305e9fa30d 100644 --- a/system/Commands/Generators/CellGenerator.php +++ b/system/Commands/Generators/CellGenerator.php @@ -77,7 +77,7 @@ public function run(array $params) $this->component = 'Cell'; $this->directory = 'Cells'; - $params = array_merge($params, ['suffix' => null]); + $params = [...$params, 'suffix' => null]; $this->templatePath = config(Generators::class)->views[$this->name]['class']; $this->template = 'cell.tpl.php'; diff --git a/system/Commands/Generators/ModelGenerator.php b/system/Commands/Generators/ModelGenerator.php index 6a817ef50eb5..9179339d002c 100644 --- a/system/Commands/Generators/ModelGenerator.php +++ b/system/Commands/Generators/ModelGenerator.php @@ -123,7 +123,7 @@ protected function prepare(string $class): string } $return = '\\' . trim($return, '\\') . '::class'; - $this->call('make:entity', array_merge([$baseClass], $this->params)); + $this->call('make:entity', [$baseClass, ...$this->params]); } else { $return = "'{$return}'"; } diff --git a/system/Commands/Translation/LocalizationFinder.php b/system/Commands/Translation/LocalizationFinder.php index d8fbbf1aad50..33f4e2571a2c 100644 --- a/system/Commands/Translation/LocalizationFinder.php +++ b/system/Commands/Translation/LocalizationFinder.php @@ -130,7 +130,7 @@ private function process(string $currentDir, string $currentLocale): void $countNewKeys += ArrayHelper::recursiveCount($languageDiff); if ($this->showNew) { - $tableRows = array_merge($this->arrayToTableRows($langFileName, $languageDiff), $tableRows); + $tableRows = [...$this->arrayToTableRows($langFileName, $languageDiff), ...$tableRows]; } else { $newLanguageKeys = array_replace_recursive($foundLanguageKeys[$langFileName], $languageStoredKeys); @@ -303,7 +303,7 @@ private function arrayToTableRows(string $langFileName, array $array): array foreach ($array as $value) { if (is_array($value)) { - $rows = array_merge($rows, $this->arrayToTableRows($langFileName, $value)); + $rows = [...$rows, ...$this->arrayToTableRows($langFileName, $value)]; continue; } diff --git a/system/Commands/Utilities/Publish.php b/system/Commands/Utilities/Publish.php index 1e4103c114d8..f1abd7433113 100644 --- a/system/Commands/Utilities/Publish.php +++ b/system/Commands/Utilities/Publish.php @@ -83,13 +83,13 @@ public function run(array $params) foreach ($publishers as $publisher) { if ($publisher->publish()) { CLI::write(lang('Publisher.publishSuccess', [ - get_class($publisher), + $publisher::class, count($publisher->getPublished()), $publisher->getDestination(), ]), 'green'); } else { CLI::error(lang('Publisher.publishFailure', [ - get_class($publisher), + $publisher::class, $publisher->getDestination(), ]), 'light_gray', 'red'); diff --git a/system/Commands/Utilities/Routes/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouteCollector.php index cc45608f21e8..ba8d6b588623 100644 --- a/system/Commands/Utilities/Routes/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouteCollector.php @@ -18,22 +18,17 @@ */ final class AutoRouteCollector { - /** - * @var string namespace to search - */ - private string $namespace; - - private string $defaultController; - private string $defaultMethod; - /** * @param string $namespace namespace to search */ - public function __construct(string $namespace, string $defaultController, string $defaultMethod) - { - $this->namespace = $namespace; - $this->defaultController = $defaultController; - $this->defaultMethod = $defaultMethod; + public function __construct( + /** + * @var string namespace to search + */ + private readonly string $namespace, + private readonly string $defaultController, + private readonly string $defaultMethod + ) { } /** diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php index 18a158cffa4f..2075dbef8ac8 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php @@ -21,44 +21,25 @@ */ final class AutoRouteCollector { - /** - * @var string namespace to search - */ - private string $namespace; - - private string $defaultController; - private string $defaultMethod; - private array $httpMethods; - - /** - * List of controllers in Defined Routes that should not be accessed via Auto-Routing. - * - * @var class-string[] - */ - private array $protectedControllers; - - /** - * @var string URI prefix for Module Routing - */ - private string $prefix; - - /** - * @param string $namespace namespace to search - */ public function __construct( - string $namespace, - string $defaultController, - string $defaultMethod, - array $httpMethods, - array $protectedControllers, - string $prefix = '' + /** + * @var string namespace to search + */ + private readonly string $namespace, + private readonly string $defaultController, + private readonly string $defaultMethod, + private readonly array $httpMethods, + /** + * List of controllers in Defined Routes that should not be accessed via Auto-Routing. + * + * @var class-string[] + */ + private readonly array $protectedControllers, + /** + * @var string URI prefix for Module Routing + */ + private string $prefix = '' ) { - $this->namespace = $namespace; - $this->defaultController = $defaultController; - $this->defaultMethod = $defaultMethod; - $this->httpMethods = $httpMethods; - $this->protectedControllers = $protectedControllers; - $this->prefix = $prefix; } /** diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php b/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php index 73da88630d5d..d1c1c5a40ee5 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php @@ -21,23 +21,16 @@ */ final class ControllerMethodReader { - /** - * @var string the default namespace - */ - private string $namespace; - - /** - * @var list - */ - private array $httpMethods; - - /** - * @param string $namespace the default namespace - */ - public function __construct(string $namespace, array $httpMethods) - { - $this->namespace = $namespace; - $this->httpMethods = $httpMethods; + public function __construct( + /** + * @var string $namespace the default namespace + */ + private readonly string $namespace, + /** + * list + */ + private readonly array $httpMethods + ) { } /** @@ -65,7 +58,7 @@ public function read(string $class, string $defaultController = 'Home', string $ $methodName = $method->getName(); foreach ($this->httpMethods as $httpVerb) { - if (strpos($methodName, strtolower($httpVerb)) === 0) { + if (str_starts_with($methodName, strtolower($httpVerb))) { // Remove HTTP verb prefix. $methodInUri = lcfirst(substr($methodName, strlen($httpVerb))); diff --git a/system/Commands/Utilities/Routes/ControllerFinder.php b/system/Commands/Utilities/Routes/ControllerFinder.php index 4611051462ea..79743a267b25 100644 --- a/system/Commands/Utilities/Routes/ControllerFinder.php +++ b/system/Commands/Utilities/Routes/ControllerFinder.php @@ -21,20 +21,15 @@ */ final class ControllerFinder { - /** - * @var string namespace to search - */ - private string $namespace; - - private FileLocatorInterface $locator; + private readonly FileLocatorInterface $locator; - /** - * @param string $namespace namespace to search - */ - public function __construct(string $namespace) - { - $this->namespace = $namespace; - $this->locator = Services::locator(); + public function __construct( + /** + * @var string namespace to search + */ + private readonly string $namespace + ) { + $this->locator = Services::locator(); } /** diff --git a/system/Commands/Utilities/Routes/ControllerMethodReader.php b/system/Commands/Utilities/Routes/ControllerMethodReader.php index 31bcde12dfb8..4d3b7c93c924 100644 --- a/system/Commands/Utilities/Routes/ControllerMethodReader.php +++ b/system/Commands/Utilities/Routes/ControllerMethodReader.php @@ -21,17 +21,12 @@ */ final class ControllerMethodReader { - /** - * @var string the default namespace - */ - private string $namespace; - - /** - * @param string $namespace the default namespace - */ - public function __construct(string $namespace) - { - $this->namespace = $namespace; + public function __construct( + /** + * @var string $namespace the default namespace + */ + private readonly string $namespace + ) { } /** diff --git a/system/Commands/Utilities/Routes/FilterCollector.php b/system/Commands/Utilities/Routes/FilterCollector.php index 0135a6a53569..3ad6cec41ac4 100644 --- a/system/Commands/Utilities/Routes/FilterCollector.php +++ b/system/Commands/Utilities/Routes/FilterCollector.php @@ -24,16 +24,14 @@ */ final class FilterCollector { - /** - * Whether to reset Defined Routes. - * - * If set to true, route filters are not found. - */ - private bool $resetRoutes; - - public function __construct(bool $resetRoutes = false) - { - $this->resetRoutes = $resetRoutes; + public function __construct( + /** + * Whether to reset Defined Routes. + * + * If set to true, route filters are not found. + */ + private readonly bool $resetRoutes = false + ) { } /** diff --git a/system/Commands/Utilities/Routes/FilterFinder.php b/system/Commands/Utilities/Routes/FilterFinder.php index cc1f6d2b05f4..f27e7e8d3d74 100644 --- a/system/Commands/Utilities/Routes/FilterFinder.php +++ b/system/Commands/Utilities/Routes/FilterFinder.php @@ -25,8 +25,8 @@ */ final class FilterFinder { - private Router $router; - private Filters $filters; + private readonly Router $router; + private readonly Filters $filters; public function __construct(?Router $router = null, ?Filters $filters = null) { @@ -65,12 +65,12 @@ public function find(string $uri): array $this->filters->initialize($uri); return $this->filters->getFilters(); - } catch (RedirectException $e) { + } catch (RedirectException) { return [ 'before' => [], 'after' => [], ]; - } catch (PageNotFoundException $e) { + } catch (PageNotFoundException) { return [ 'before' => [''], 'after' => [''], diff --git a/system/Commands/Utilities/Routes/SampleURIGenerator.php b/system/Commands/Utilities/Routes/SampleURIGenerator.php index 43d1934438bb..c0832a382eff 100644 --- a/system/Commands/Utilities/Routes/SampleURIGenerator.php +++ b/system/Commands/Utilities/Routes/SampleURIGenerator.php @@ -22,7 +22,7 @@ */ final class SampleURIGenerator { - private RouteCollection $routes; + private readonly RouteCollection $routes; /** * Sample URI path for placeholder. @@ -52,7 +52,7 @@ public function get(string $routeKey): string { $sampleUri = $routeKey; - if (strpos($routeKey, '{locale}') !== false) { + if (str_contains($routeKey, '{locale}')) { $sampleUri = str_replace( '{locale}', config(App::class)->defaultLocale, diff --git a/system/Common.php b/system/Common.php index 0f8aa3e7ad27..1e6780298e83 100644 --- a/system/Common.php +++ b/system/Common.php @@ -92,29 +92,18 @@ function clean_path(string $path): string // Resolve relative paths try { $path = realpath($path) ?: $path; - } catch (ErrorException|ValueError $e) { + } catch (ErrorException|ValueError) { $path = 'error file path: ' . urlencode($path); } - switch (true) { - case strpos($path, APPPATH) === 0: - return 'APPPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(APPPATH)); - - case strpos($path, SYSTEMPATH) === 0: - return 'SYSTEMPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(SYSTEMPATH)); - - case strpos($path, FCPATH) === 0: - return 'FCPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(FCPATH)); - - case defined('VENDORPATH') && strpos($path, VENDORPATH) === 0: - return 'VENDORPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(VENDORPATH)); - - case strpos($path, ROOTPATH) === 0: - return 'ROOTPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(ROOTPATH)); - - default: - return $path; - } + return match (true) { + str_starts_with($path, APPPATH) => 'APPPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(APPPATH)), + str_starts_with($path, SYSTEMPATH) => 'SYSTEMPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(SYSTEMPATH)), + str_starts_with($path, FCPATH) => 'FCPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(FCPATH)), + defined('VENDORPATH') && str_starts_with($path, VENDORPATH) => 'VENDORPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(VENDORPATH)), + str_starts_with($path, ROOTPATH) => 'ROOTPATH' . DIRECTORY_SEPARATOR . substr($path, strlen(ROOTPATH)), + default => $path, + }; } } @@ -383,21 +372,13 @@ function env(string $key, $default = null) } // Handle any boolean values - switch (strtolower($value)) { - case 'true': - return true; - - case 'false': - return false; - - case 'empty': - return ''; - - case 'null': - return null; - } - - return $value; + return match (strtolower($value)) { + 'true' => true, + 'false' => false, + 'empty' => '', + 'null' => null, + default => $value, + }; } } @@ -592,7 +573,7 @@ function helper($filenames): void $appHelper = null; $localIncludes = []; - if (strpos($filename, '_helper') === false) { + if (! str_contains($filename, '_helper')) { $filename .= '_helper'; } @@ -603,7 +584,7 @@ function helper($filenames): void // If the file is namespaced, we'll just grab that // file and not search for any others - if (strpos($filename, '\\') !== false) { + if (str_contains($filename, '\\')) { $path = $loader->locateFile($filename, 'Helpers'); if (empty($path)) { @@ -617,9 +598,9 @@ function helper($filenames): void $paths = $loader->search('Helpers/' . $filename); foreach ($paths as $path) { - if (strpos($path, APPPATH . 'Helpers' . DIRECTORY_SEPARATOR) === 0) { + if (str_starts_with($path, APPPATH . 'Helpers' . DIRECTORY_SEPARATOR)) { $appHelper = $path; - } elseif (strpos($path, SYSTEMPATH . 'Helpers' . DIRECTORY_SEPARATOR) === 0) { + } elseif (str_starts_with($path, SYSTEMPATH . 'Helpers' . DIRECTORY_SEPARATOR)) { $systemHelper = $path; } else { $localIncludes[] = $path; @@ -1209,7 +1190,7 @@ function view_cell(string $library, $params = null, int $ttl = 0, ?string $cache */ function class_basename($class) { - $class = is_object($class) ? get_class($class) : $class; + $class = is_object($class) ? $class::class : $class; return basename(str_replace('\\', '/', $class)); } @@ -1228,7 +1209,7 @@ function class_basename($class) function class_uses_recursive($class) { if (is_object($class)) { - $class = get_class($class); + $class = $class::class; } $results = []; diff --git a/system/ComposerScripts.php b/system/ComposerScripts.php index 021079da468d..a3cda28fe063 100644 --- a/system/ComposerScripts.php +++ b/system/ComposerScripts.php @@ -71,7 +71,7 @@ public static function postUpdate() foreach (self::$dependencies as $key => $dependency) { // Kint may be removed. - if (! is_dir($dependency['from']) && strpos($key, 'kint') === 0) { + if (! is_dir($dependency['from']) && str_starts_with($key, 'kint')) { continue; } diff --git a/system/Config/AutoloadConfig.php b/system/Config/AutoloadConfig.php index eb210f626d9a..411f9bd41760 100644 --- a/system/Config/AutoloadConfig.php +++ b/system/Config/AutoloadConfig.php @@ -144,8 +144,8 @@ public function __construct() $this->classmap['CIDatabaseTestCase'] = SYSTEMPATH . 'Test/CIDatabaseTestCase.php'; } - $this->psr4 = array_merge($this->corePsr4, $this->psr4); - $this->classmap = array_merge($this->coreClassmap, $this->classmap); + $this->psr4 = [...$this->corePsr4, ...$this->psr4]; + $this->classmap = [...$this->coreClassmap, ...$this->classmap]; $this->files = [...$this->coreFiles, ...$this->files]; } } diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 216ce81fd5e9..fbe50e1c48fc 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -120,10 +120,10 @@ public function __construct() $this->initEnvValue($this->{$property}, $property, $prefix, $shortPrefix); if ($this instanceof Encryption && $property === 'key') { - if (strpos($this->{$property}, 'hex2bin:') === 0) { + if (str_starts_with($this->{$property}, 'hex2bin:')) { // Handle hex2bin prefix $this->{$property} = hex2bin(substr($this->{$property}, 8)); - } elseif (strpos($this->{$property}, 'base64:') === 0) { + } elseif (str_starts_with($this->{$property}, 'base64:')) { // Handle base64 prefix $this->{$property} = base64_decode(substr($this->{$property}, 7), true); } @@ -261,7 +261,7 @@ protected function registerProperties() foreach ($properties as $property => $value) { if (isset($this->{$property}) && is_array($this->{$property}) && is_array($value)) { - $this->{$property} = array_merge($this->{$property}, $value); + $this->{$property} = [...$this->{$property}, ...$value]; } else { $this->{$property} = $value; } diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 970977dd416a..d07889b2d41c 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -266,7 +266,7 @@ public static function __callStatic(string $name, array $arguments) public static function serviceExists(string $name): ?string { static::buildServicesCache(); - $services = array_merge(self::$serviceNames, [Services::class]); + $services = [...self::$serviceNames, Services::class]; $name = strtolower($name); foreach ($services as $service) { diff --git a/system/Config/DotEnv.php b/system/Config/DotEnv.php index 05ecab900c3e..01c51ebf2f9e 100644 --- a/system/Config/DotEnv.php +++ b/system/Config/DotEnv.php @@ -68,12 +68,12 @@ public function parse(): ?array foreach ($lines as $line) { // Is it a comment? - if (strpos(trim($line), '#') === 0) { + if (str_starts_with(trim($line), '#')) { continue; } // If there is an equal sign, then we know we are assigning a variable. - if (strpos($line, '=') !== false) { + if (str_contains($line, '=')) { [$name, $value] = $this->normaliseVariable($line); $vars[$name] = $value; $this->setVariable($name, $value); @@ -112,7 +112,7 @@ protected function setVariable(string $name, string $value = '') public function normaliseVariable(string $name, string $value = ''): array { // Split our compound string into its parts. - if (strpos($name, '=') !== false) { + if (str_contains($name, '=')) { [$name, $value] = explode('=', $name, 2); } @@ -192,7 +192,7 @@ protected function sanitizeValue(string $value): string */ protected function resolveNestedVariables(string $value): string { - if (strpos($value, '$') !== false) { + if (str_contains($value, '$')) { $value = preg_replace_callback( '/\${([a-zA-Z0-9_\.]+)}/', function ($matchedPatterns) { diff --git a/system/Config/Factories.php b/system/Config/Factories.php index 253cd3f7a7c9..72c561e43415 100644 --- a/system/Config/Factories.php +++ b/system/Config/Factories.php @@ -36,7 +36,7 @@ final class Factories * * @var array> */ - private static $options = []; + private static array $options = []; /** * Explicit options for the Config @@ -64,7 +64,7 @@ final class Factories * * @var array> */ - private static $aliases = []; + private static array $aliases = []; /** * Store for instances of any component that @@ -77,7 +77,7 @@ final class Factories * * @var array> */ - private static $instances = []; + private static array $instances = []; /** * Whether the component instances are updated? @@ -86,7 +86,7 @@ final class Factories * * @internal For caching only */ - private static $updated = []; + private static array $updated = []; /** * Define the class to load. You can *override* the concrete class. @@ -316,7 +316,7 @@ class_exists($alias, false) */ private static function isNamespaced(string $alias): bool { - return strpos($alias, '\\') !== false; + return str_contains($alias, '\\'); } /** @@ -334,10 +334,10 @@ private static function verifyPreferApp(array $options, string $alias): bool // Special case for Config since its App namespace is actually \Config if (self::isConfig($options['component'])) { - return strpos($alias, 'Config') === 0; + return str_starts_with($alias, 'Config'); } - return strpos($alias, APP_NAMESPACE) === 0; + return str_starts_with($alias, APP_NAMESPACE); } /** @@ -461,7 +461,7 @@ public static function injectMock(string $component, string $alias, object $inst // Force a configuration to exist for this component self::getOptions($component); - $class = get_class($instance); + $class = $instance::class; self::$instances[$component][$class] = $instance; self::$aliases[$component][$alias] = $class; diff --git a/system/Config/View.php b/system/Config/View.php index 101b67f580d0..4aff08471ac0 100644 --- a/system/Config/View.php +++ b/system/Config/View.php @@ -122,8 +122,8 @@ class View extends BaseConfig */ public function __construct() { - $this->filters = array_merge($this->coreFilters, $this->filters); - $this->plugins = array_merge($this->corePlugins, $this->plugins); + $this->filters = [...$this->coreFilters, ...$this->filters]; + $this->plugins = [...$this->corePlugins, ...$this->plugins]; parent::__construct(); } diff --git a/system/Cookie/Cookie.php b/system/Cookie/Cookie.php index 68a748cb30eb..96248099a02e 100644 --- a/system/Cookie/Cookie.php +++ b/system/Cookie/Cookie.php @@ -19,6 +19,7 @@ use InvalidArgumentException; use LogicException; use ReturnTypeWillChange; +use Stringable; /** * A `Cookie` class represents an immutable HTTP cookie value object. @@ -41,7 +42,7 @@ * @template-implements ArrayAccess * @see \CodeIgniter\Cookie\CookieTest */ -class Cookie implements ArrayAccess, CloneableCookieInterface +class Cookie implements ArrayAccess, CloneableCookieInterface, Stringable { /** * @var string @@ -159,7 +160,6 @@ public static function setDefaults($config = []) // ========================================================================= // CONSTRUCTORS // ========================================================================= - /** * Create a new Cookie instance from a `Set-Cookie` header. * @@ -180,7 +180,7 @@ public static function fromHeaderString(string $cookie, bool $raw = false) unset($part); foreach ($parts as $part) { - if (strpos($part, '=') !== false) { + if (str_contains($part, '=')) { [$attr, $val] = explode('=', $part); } else { $attr = $part; @@ -245,7 +245,6 @@ final public function __construct(string $name, string $value = '', array $optio // ========================================================================= // GETTERS // ========================================================================= - /** * {@inheritDoc} */ @@ -398,7 +397,6 @@ public function getOptions(): array // ========================================================================= // CLONING // ========================================================================= - /** * {@inheritDoc} */ @@ -563,7 +561,6 @@ public function withRaw(bool $raw = true) // ========================================================================= // ARRAY ACCESS FOR BC // ========================================================================= - /** * Whether an offset exists. * @@ -621,7 +618,6 @@ public function offsetUnset($offset): void // ========================================================================= // CONVERTERS // ========================================================================= - /** * {@inheritDoc} */ @@ -723,7 +719,6 @@ protected static function convertExpiresTimestamp($expires = 0): int // ========================================================================= // VALIDATION // ========================================================================= - /** * Validates the cookie name per RFC 2616. * @@ -750,11 +745,11 @@ protected function validateName(string $name, bool $raw): void */ protected function validatePrefix(string $prefix, bool $secure, string $path, string $domain): void { - if (strpos($prefix, '__Secure-') === 0 && ! $secure) { + if (str_starts_with($prefix, '__Secure-') && ! $secure) { throw CookieException::forInvalidSecurePrefix(); } - if (strpos($prefix, '__Host-') === 0 && (! $secure || $domain !== '' || $path !== '/')) { + if (str_starts_with($prefix, '__Host-') && (! $secure || $domain !== '' || $path !== '/')) { throw CookieException::forInvalidHostPrefix(); } } diff --git a/system/Cookie/CookieStore.php b/system/Cookie/CookieStore.php index d893a4add116..867ffcecf976 100644 --- a/system/Cookie/CookieStore.php +++ b/system/Cookie/CookieStore.php @@ -223,7 +223,7 @@ public function getIterator(): Traversable protected function validateCookies(array $cookies): void { foreach ($cookies as $index => $cookie) { - $type = is_object($cookie) ? get_class($cookie) : gettype($cookie); + $type = get_debug_type($cookie); if (! $cookie instanceof Cookie) { throw CookieException::forInvalidCookieInstance([static::class, Cookie::class, $type, $index]); diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index badf2d35cdfc..5c86942be008 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -310,7 +310,7 @@ public function __construct($tableName, ConnectionInterface $db, ?array $options $this->db = $db; // If it contains `,`, it has multiple tables - if (is_string($tableName) && strpos($tableName, ',') === false) { + if (is_string($tableName) && ! str_contains($tableName, ',')) { $this->tableName = $tableName; // @TODO remove alias if exists } else { $this->tableName = ''; @@ -508,7 +508,7 @@ protected function maxMinAvgSum(string $select = '', string $alias = '', string throw DataException::forEmptyInputGiven('Select'); } - if (strpos($select, ',') !== false) { + if (str_contains($select, ',')) { throw DataException::forInvalidArgument('column name not separated by comma'); } @@ -535,7 +535,7 @@ protected function maxMinAvgSum(string $select = '', string $alias = '', string */ protected function createAliasFromTable(string $item): string { - if (strpos($item, '.') !== false) { + if (str_contains($item, '.')) { $item = explode('.', $item); return end($item); @@ -571,7 +571,7 @@ public function from($from, bool $overwrite = false): self } foreach ((array) $from as $table) { - if (strpos($table, ',') !== false) { + if (str_contains($table, ',')) { $this->from(explode(',', $table)); } else { $table = trim($table); @@ -760,7 +760,7 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type $op = trim(current($op)); // Does the key end with operator? - if (substr($k, -strlen($op)) === $op) { + if (str_ends_with($k, $op)) { $k = rtrim(substr($k, 0, -strlen($op))); $op = " {$op}"; } else { @@ -2318,7 +2318,7 @@ public function insert($set = null, ?bool $escape = null) */ protected function removeAlias(string $from): string { - if (strpos($from, ' ') !== false) { + if (str_contains($from, ' ')) { // if the alias is written with the AS keyword, remove it $from = preg_replace('/\s+AS\s+/i', ' ', $from); @@ -2966,12 +2966,12 @@ protected function trackAliases($table) // Does the string contain a comma? If so, we need to separate // the string into discreet statements - if (strpos($table, ',') !== false) { + if (str_contains($table, ',')) { return $this->trackAliases(explode(',', $table)); } // if a table alias is used we can recognize it by a space - if (strpos($table, ' ') !== false) { + if (str_contains($table, ' ')) { // if the alias is written with the AS keyword, remove it $table = preg_replace('/\s+AS\s+/i', ' ', $table); @@ -3111,11 +3111,11 @@ protected function compileWhereHaving(string $qbKey): string if (! empty($matches[4])) { $protectIdentifiers = false; - if (strpos($matches[4], '.') !== false) { + if (str_contains($matches[4], '.')) { $protectIdentifiers = true; } - if (strpos($matches[4], ':') === false) { + if (! str_contains($matches[4], ':')) { $matches[4] = $this->db->protectIdentifiers(trim($matches[4]), false, $protectIdentifiers); } diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 6d92965f0b94..5e40aee5e784 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1067,7 +1067,7 @@ public function protectIdentifiers($item, bool $prefixSingle = false, ?bool $pro // Break the string apart if it contains periods, then insert the table prefix // in the correct location, assuming the period doesn't indicate that we're dealing // with an alias. While we're at it, we will escape the components - if (strpos($item, '.') !== false) { + if (str_contains($item, '.')) { return $this->protectDotItem($item, $alias, $protectIdentifiers, $fieldExists); } @@ -1079,11 +1079,11 @@ public function protectIdentifiers($item, bool $prefixSingle = false, ?bool $pro // Is there a table prefix? If not, no need to insert it if ($this->DBPrefix !== '') { // Verify table prefix and replace if necessary - if ($this->swapPre !== '' && strpos($item, $this->swapPre) === 0) { + if ($this->swapPre !== '' && str_starts_with($item, $this->swapPre)) { $item = preg_replace('/^' . $this->swapPre . '(\S+?)/', $this->DBPrefix . '\\1', $item); } // Do we prefix an item with no segments? - elseif ($prefixSingle === true && strpos($item, $this->DBPrefix) !== 0) { + elseif ($prefixSingle === true && ! str_starts_with($item, $this->DBPrefix)) { $item = $this->DBPrefix . $item; } } @@ -1145,11 +1145,11 @@ private function protectDotItem(string $item, string $alias, bool $protectIdenti } // Verify table prefix and replace if necessary - if ($this->swapPre !== '' && strpos($parts[$i], $this->swapPre) === 0) { + if ($this->swapPre !== '' && str_starts_with($parts[$i], $this->swapPre)) { $parts[$i] = preg_replace('/^' . $this->swapPre . '(\S+?)/', $this->DBPrefix . '\\1', $parts[$i]); } // We only add the table prefix if it does not already exist - elseif (strpos($parts[$i], $this->DBPrefix) !== 0) { + elseif (! str_starts_with($parts[$i], $this->DBPrefix)) { $parts[$i] = $this->DBPrefix . $parts[$i]; } @@ -1192,7 +1192,7 @@ public function escapeIdentifiers($item) if (ctype_digit($item) || $item[0] === "'" || ($this->escapeChar !== '"' && $item[0] === '"') - || strpos($item, '(') !== false) { + || str_contains($item, '(')) { return $item; } @@ -1212,7 +1212,7 @@ public function escapeIdentifiers($item) foreach ($this->reservedIdentifiers as $id) { /** @psalm-suppress NoValue I don't know why ERROR. */ - if (strpos($item, '.' . $id) !== false) { + if (str_contains($item, '.' . $id)) { return preg_replace( '/' . $this->pregEscapeChar[0] . '?([^' . $this->pregEscapeChar[1] . '\.]+)' . $this->pregEscapeChar[1] . '?\./i', $this->pregEscapeChar[2] . '$1' . $this->pregEscapeChar[3] . '.', @@ -1262,7 +1262,7 @@ abstract public function affectedRows(): int; public function escape($str) { if (is_array($str)) { - return array_map([&$this, 'escape'], $str); + return array_map($this->escape(...), $str); } /** @psalm-suppress NoValue I don't know why ERROR. */ @@ -1358,7 +1358,7 @@ public function callFunction(string $functionName, ...$params): bool { $driver = $this->getDriverFunctionPrefix(); - if (strpos($driver, $functionName) === false) { + if (! str_contains($driver, $functionName)) { $functionName = $driver . $functionName; } diff --git a/system/Database/Database.php b/system/Database/Database.php index 2818fe220928..7d8921663faf 100644 --- a/system/Database/Database.php +++ b/system/Database/Database.php @@ -44,7 +44,7 @@ public function load(array $params = [], string $alias = '') throw new InvalidArgumentException('You must supply the parameter: alias.'); } - if (! empty($params['DSN']) && strpos($params['DSN'], '://') !== false) { + if (! empty($params['DSN']) && str_contains($params['DSN'], '://')) { $params = $this->parseDSN($params); } @@ -130,7 +130,7 @@ protected function parseDSN(array $params): array */ protected function initDriver(string $driver, string $class, $argument): object { - $classname = (strpos($driver, '\\') === false) + $classname = (! str_contains($driver, '\\')) ? "CodeIgniter\\Database\\{$driver}\\{$class}" : $driver . '\\' . $class; diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 57e43bf199fe..f7161d752cbb 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -368,7 +368,7 @@ public function addField($field) ]); $this->addKey('id', true); } else { - if (strpos($field, ' ') === false) { + if (! str_contains($field, ' ')) { throw new InvalidArgumentException('Field information is required for that operation.'); } @@ -624,7 +624,7 @@ public function dropTable(string $tableName, bool $ifExists = false, bool $casca return false; } - if ($this->db->DBPrefix && strpos($tableName, $this->db->DBPrefix) === 0) { + if ($this->db->DBPrefix && str_starts_with($tableName, $this->db->DBPrefix)) { $tableName = substr($tableName, strlen($this->db->DBPrefix)); } @@ -1094,7 +1094,7 @@ public function processIndexes(string $table): bool $this->fields = $fields; if ($this->foreignKeys !== []) { - $sqls = array_merge($sqls, $this->_processForeignKeys($table, true)); + $sqls = [...$sqls, ...$this->_processForeignKeys($table, true)]; } foreach ($sqls as $sql) { diff --git a/system/Database/MigrationRunner.php b/system/Database/MigrationRunner.php index 4b342eeaac39..0beac62fe701 100644 --- a/system/Database/MigrationRunner.php +++ b/system/Database/MigrationRunner.php @@ -447,7 +447,7 @@ public function findNamespaceMigrations(string $namespace): array */ protected function migrationFromFile(string $path, string $namespace) { - if (substr($path, -4) !== '.php') { + if (! str_ends_with($path, '.php')) { return false; } diff --git a/system/Database/OCI8/Connection.php b/system/Database/OCI8/Connection.php index 8cb7e3a4a766..510655f38686 100644 --- a/system/Database/OCI8/Connection.php +++ b/system/Database/OCI8/Connection.php @@ -221,7 +221,7 @@ protected function execute(string $sql) public function parseInsertTableName(string $sql): string { $commentStrippedSql = preg_replace(['/\/\*(.|\n)*?\*\//m', '/--.+/'], '', $sql); - $isInsertQuery = strpos(strtoupper(ltrim($commentStrippedSql)), 'INSERT') === 0; + $isInsertQuery = str_starts_with(strtoupper(ltrim($commentStrippedSql)), 'INSERT'); if (! $isInsertQuery) { return ''; @@ -230,7 +230,7 @@ public function parseInsertTableName(string $sql): string preg_match('/(?is)\b(?:into)\s+("?\w+"?)/', $commentStrippedSql, $match); $tableName = $match[1] ?? ''; - return strpos($tableName, '"') === 0 ? trim($tableName, '"') : strtoupper($tableName); + return str_starts_with($tableName, '"') ? trim($tableName, '"') : strtoupper($tableName); } /** @@ -267,7 +267,7 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n */ protected function _listColumns(string $table = ''): string { - if (strpos($table, '.') !== false) { + if (str_contains($table, '.')) { sscanf($table, '%[^.].%s', $owner, $table); } else { $owner = $this->username; @@ -287,7 +287,7 @@ protected function _listColumns(string $table = ''): string */ protected function _fieldData(string $table): array { - if (strpos($table, '.') !== false) { + if (str_contains($table, '.')) { sscanf($table, '%[^.].%s', $owner, $table); } else { $owner = $this->username; @@ -335,7 +335,7 @@ protected function _fieldData(string $table): array */ protected function _indexData(string $table): array { - if (strpos($table, '.') !== false) { + if (str_contains($table, '.')) { sscanf($table, '%[^.].%s', $owner, $table); } else { $owner = $this->username; @@ -633,7 +633,7 @@ protected function buildDSN() return; } - $isEasyConnectableHostName = $this->hostname !== '' && strpos($this->hostname, '/') === false && strpos($this->hostname, ':') === false; + $isEasyConnectableHostName = $this->hostname !== '' && ! str_contains($this->hostname, '/') && ! str_contains($this->hostname, ':'); $easyConnectablePort = ! empty($this->port) && ctype_digit($this->port) ? ':' . $this->port : ''; $easyConnectableDatabase = $this->database !== '' ? '/' . ltrim($this->database, '/') : ''; diff --git a/system/Database/OCI8/Forge.php b/system/Database/OCI8/Forge.php index 6e1e85f666a1..be2dc2181f0c 100644 --- a/system/Database/OCI8/Forge.php +++ b/system/Database/OCI8/Forge.php @@ -122,7 +122,7 @@ protected function _alterTable(string $alterType, string $table, $field) // so add null constraint is used only when it is different from the current null constraint. // If a not null constraint is added to a column with a not null constraint, // ORA-01442 will occur. - $wantToAddNull = strpos($field[$i]['null'], ' NOT') === false; + $wantToAddNull = ! str_contains($field[$i]['null'], ' NOT'); $currentNullable = $nullableMap[$field[$i]['name']]; if ($wantToAddNull === true && $currentNullable === true) { @@ -188,7 +188,7 @@ protected function _processColumn(array $field): string { $constraint = ''; // @todo: can't cover multi pattern when set type. - if ($field['type'] === 'VARCHAR2' && strpos($field['length'], "('") === 0) { + if ($field['type'] === 'VARCHAR2' && str_starts_with($field['length'], "('")) { $constraint = ' CHECK(' . $this->db->escapeIdentifiers($field['name']) . ' IN ' . $field['length'] . ')'; diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index e9763089a90f..8fda3a640402 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -306,7 +306,7 @@ protected function _like_statement(?string $prefix, string $column, ?string $not public function join(string $table, $cond, string $type = '', ?bool $escape = null) { if (! in_array('FULL OUTER', $this->joinTypes, true)) { - $this->joinTypes = array_merge($this->joinTypes, ['FULL OUTER']); + $this->joinTypes = [...$this->joinTypes, 'FULL OUTER']; } return parent::join($table, $cond, $type, $escape); diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index 56905ec922d2..53fe40ea4ca0 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -353,10 +353,10 @@ protected function _indexData(string $table): array $_fields = explode(',', preg_replace('/^.*\((.+?)\)$/', '$1', trim($row->indexdef))); $obj->fields = array_map(static fn ($v) => trim($v), $_fields); - if (strpos($row->indexdef, 'CREATE UNIQUE INDEX pk') === 0) { + if (str_starts_with($row->indexdef, 'CREATE UNIQUE INDEX pk')) { $obj->type = 'PRIMARY'; } else { - $obj->type = (strpos($row->indexdef, 'CREATE UNIQUE') === 0) ? 'UNIQUE' : 'INDEX'; + $obj->type = (str_starts_with($row->indexdef, 'CREATE UNIQUE')) ? 'UNIQUE' : 'INDEX'; } $retVal[$obj->name] = $obj; @@ -493,7 +493,7 @@ protected function buildDSN() } // If UNIX sockets are used, we shouldn't set a port - if (strpos($this->hostname, '/') !== false) { + if (str_contains($this->hostname, '/')) { $this->port = ''; } diff --git a/system/Database/Query.php b/system/Database/Query.php index 897a668f1376..898951e09bce 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -11,10 +11,12 @@ namespace CodeIgniter\Database; +use Stringable; + /** * Query builder */ -class Query implements QueryInterface +class Query implements QueryInterface, Stringable { /** * The query string, as provided by the user. diff --git a/system/Database/RawSql.php b/system/Database/RawSql.php index efa97d30736c..e45921d42e7a 100644 --- a/system/Database/RawSql.php +++ b/system/Database/RawSql.php @@ -11,10 +11,12 @@ namespace CodeIgniter\Database; +use Stringable; + /** * @see \CodeIgniter\Database\RawSqlTest */ -class RawSql +class RawSql implements Stringable { /** * @var string Raw SQL string diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index 5e3e4a73bb11..b2c207f6dc3f 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -69,7 +69,7 @@ protected function _fromTables(): string $from = []; foreach ($this->QBFrom as $value) { - $from[] = strpos($value, '(SELECT') === 0 ? $value : $this->getFullName($value); + $from[] = str_starts_with($value, '(SELECT') ? $value : $this->getFullName($value); } return implode(', ', $from); @@ -280,7 +280,7 @@ private function getFullName(string $table): string { $alias = ''; - if (strpos($table, ' ') !== false) { + if (str_contains($table, ' ')) { $alias = explode(' ', $table); $table = array_shift($alias); $alias = ' ' . implode(' ', $alias); @@ -439,7 +439,7 @@ protected function maxMinAvgSum(string $select = '', string $alias = '', string throw DataException::forEmptyInputGiven('Select'); } - if (strpos($select, ',') !== false) { + if (str_contains($select, ',')) { throw DataException::forInvalidArgument('Column name not separated by comma'); } diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index f1a9fb0b433a..784f527790a1 100755 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -121,7 +121,7 @@ public function connect(bool $persistent = false) unset($connection['UID'], $connection['PWD']); } - if (strpos($this->hostname, ',') === false && $this->port !== '') { + if (! str_contains($this->hostname, ',') && $this->port !== '') { $this->hostname .= ', ' . $this->port; } @@ -253,10 +253,10 @@ protected function _indexData(string $table): array $_fields = explode(',', trim($row->index_keys)); $obj->fields = array_map(static fn ($v) => trim($v), $_fields); - if (strpos($row->index_description, 'primary key located on') !== false) { + if (str_contains($row->index_description, 'primary key located on')) { $obj->type = 'PRIMARY'; } else { - $obj->type = (strpos($row->index_description, 'nonclustered, unique') !== false) ? 'UNIQUE' : 'INDEX'; + $obj->type = (str_contains($row->index_description, 'nonclustered, unique')) ? 'UNIQUE' : 'INDEX'; } $retVal[$obj->name] = $obj; diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index f41c8e4de792..dcebba75a9ab 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -81,7 +81,7 @@ public function connect(bool $persistent = false) } try { - if ($this->database !== ':memory:' && strpos($this->database, DIRECTORY_SEPARATOR) === false) { + if ($this->database !== ':memory:' && ! str_contains($this->database, DIRECTORY_SEPARATOR)) { $this->database = WRITEPATH . $this->database; } diff --git a/system/Database/SQLite3/Forge.php b/system/Database/SQLite3/Forge.php index b1dcb1dd599b..6487c94bbc4c 100644 --- a/system/Database/SQLite3/Forge.php +++ b/system/Database/SQLite3/Forge.php @@ -143,7 +143,7 @@ protected function _alterTable(string $alterType, string $table, $field) */ protected function _processColumn(array $field): string { - if ($field['type'] === 'TEXT' && strpos($field['length'], "('") === 0) { + if ($field['type'] === 'TEXT' && str_starts_with($field['length'], "('")) { $field['type'] .= ' CHECK(' . $this->db->escapeIdentifiers($field['name']) . ' IN ' . $field['length'] . ')'; } diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php index 879437da6f6a..244bc20e1622 100644 --- a/system/Database/SQLite3/Table.php +++ b/system/Database/SQLite3/Table.php @@ -96,7 +96,7 @@ public function fromTable(string $table) $prefix = $this->db->DBPrefix; - if (! empty($prefix) && strpos($table, $prefix) === 0) { + if (! empty($prefix) && str_starts_with($table, $prefix)) { $table = substr($table, strlen($prefix)); } @@ -271,7 +271,7 @@ public function addForeignKey(array $foreignKeys) $fk[] = $obj; } - $this->foreignKeys = array_merge($this->foreignKeys, $fk); + $this->foreignKeys = [...$this->foreignKeys, ...$fk]; return $this; } diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index 749f6f34d5c7..ebd65e5a0387 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -123,7 +123,7 @@ public function call(string $class) throw new InvalidArgumentException('No seeder was specified.'); } - if (strpos($class, '\\') === false) { + if (! str_contains($class, '\\')) { $path = $this->seedPath . str_replace('.php', '', $class) . '.php'; if (! is_file($path)) { diff --git a/system/Debug/BaseExceptionHandler.php b/system/Debug/BaseExceptionHandler.php index 8b67d2153f9f..fcd6429b07d2 100644 --- a/system/Debug/BaseExceptionHandler.php +++ b/system/Debug/BaseExceptionHandler.php @@ -81,8 +81,8 @@ protected function collectVars(Throwable $exception, int $statusCode): array } return [ - 'title' => get_class($exception), - 'type' => get_class($exception), + 'title' => $exception::class, + 'type' => $exception::class, 'code' => $statusCode, 'message' => $exception->getMessage(), 'file' => $exception->getFile(), @@ -114,7 +114,7 @@ private function maskData($args, array $keysToMask, string $path = '') $explode = explode('/', $keyToMask); $index = end($explode); - if (strpos(strrev($path . '/' . $index), strrev($keyToMask)) === 0) { + if (str_starts_with(strrev($path . '/' . $index), strrev($keyToMask))) { if (is_array($args) && array_key_exists($index, $args)) { $args[$index] = '******************'; } elseif ( @@ -176,7 +176,7 @@ protected static function highlightFile(string $file, int $lineNumber, int $line try { $source = file_get_contents($file); - } catch (Throwable $e) { + } catch (Throwable) { return false; } diff --git a/system/Debug/ExceptionHandler.php b/system/Debug/ExceptionHandler.php index 63449888ffb5..51e85db3013c 100644 --- a/system/Debug/ExceptionHandler.php +++ b/system/Debug/ExceptionHandler.php @@ -54,7 +54,7 @@ public function handle( if ($request instanceof IncomingRequest) { try { $response->setStatusCode($statusCode); - } catch (HTTPException $e) { + } catch (HTTPException) { // Workaround for invalid HTTP status code. $statusCode = 500; $response->setStatusCode($statusCode); @@ -73,7 +73,7 @@ public function handle( ); } - if (strpos($request->getHeaderLine('accept'), 'text/html') === false) { + if (! str_contains($request->getHeaderLine('accept'), 'text/html')) { $data = (ENVIRONMENT === 'development' || ENVIRONMENT === 'testing') ? $this->collectVars($exception, $statusCode) : ''; diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index da5ce9373753..dfb5b81bd7bd 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -106,8 +106,8 @@ public function __construct(ExceptionsConfig $config) */ public function initialize() { - set_exception_handler([$this, 'exceptionHandler']); - set_error_handler([$this, 'errorHandler']); + set_exception_handler($this->exceptionHandler(...)); + set_error_handler($this->errorHandler(...)); register_shutdown_function([$this, 'shutdownHandler']); } @@ -130,7 +130,7 @@ public function exceptionHandler(Throwable $exception) $uri = $this->request->getPath() === '' ? '/' : $this->request->getPath(); $routeInfo = '[Method: ' . $this->request->getMethod() . ', Route: ' . $uri . ']'; - log_message('critical', get_class($exception) . ": {message}\n{routeInfo}\nin {exFile} on line {exLine}.\n{trace}", [ + log_message('critical', $exception::class . ": {message}\n{routeInfo}\nin {exFile} on line {exLine}.\n{trace}", [ 'message' => $exception->getMessage(), 'routeInfo' => $routeInfo, 'exFile' => clean_path($exception->getFile()), // {file} refers to THIS file @@ -144,7 +144,7 @@ public function exceptionHandler(Throwable $exception) while ($prevException = $last->getPrevious()) { $last = $prevException; - log_message('critical', '[Caused by] ' . get_class($prevException) . ": {message}\nin {exFile} on line {exLine}.\n{trace}", [ + log_message('critical', '[Caused by] ' . $prevException::class . ": {message}\nin {exFile} on line {exLine}.\n{trace}", [ 'message' => $prevException->getMessage(), 'exFile' => clean_path($prevException->getFile()), // {file} refers to THIS file 'exLine' => $prevException->getLine(), // {line} refers to THIS line @@ -173,7 +173,7 @@ public function exceptionHandler(Throwable $exception) if (! is_cli()) { try { $this->response->setStatusCode($statusCode); - } catch (HTTPException $e) { + } catch (HTTPException) { // Workaround for invalid HTTP status code. $statusCode = 500; $this->response->setStatusCode($statusCode); @@ -183,7 +183,7 @@ public function exceptionHandler(Throwable $exception) header(sprintf('HTTP/%s %s %s', $this->request->getProtocolVersion(), $this->response->getStatusCode(), $this->response->getReasonPhrase()), true, $statusCode); } - if (strpos($this->request->getHeaderLine('accept'), 'text/html') === false) { + if (! str_contains($this->request->getHeaderLine('accept'), 'text/html')) { $this->respond(ENVIRONMENT === 'development' ? $this->collectVars($exception, $statusCode) : '', $statusCode)->send(); exit($exitCode); @@ -241,7 +241,7 @@ public function shutdownHandler() if ($this->exceptionCaughtByExceptionHandler instanceof Throwable) { $message .= "\n【Previous Exception】\n" - . get_class($this->exceptionCaughtByExceptionHandler) . "\n" + . $this->exceptionCaughtByExceptionHandler::class . "\n" . $this->exceptionCaughtByExceptionHandler->getMessage() . "\n" . $this->exceptionCaughtByExceptionHandler->getTraceAsString(); } @@ -353,8 +353,8 @@ protected function collectVars(Throwable $exception, int $statusCode): array } return [ - 'title' => get_class($exception), - 'type' => get_class($exception), + 'title' => $exception::class, + 'type' => $exception::class, 'code' => $statusCode, 'message' => $exception->getMessage(), 'file' => $exception->getFile(), @@ -394,7 +394,7 @@ private function maskData($args, array $keysToMask, string $path = '') $explode = explode('/', $keyToMask); $index = end($explode); - if (strpos(strrev($path . '/' . $index), strrev($keyToMask)) === 0) { + if (str_starts_with(strrev($path . '/' . $index), strrev($keyToMask))) { if (is_array($args) && array_key_exists($index, $args)) { $args[$index] = '******************'; } elseif ( @@ -478,25 +478,13 @@ private function handleDeprecationError(string $message, ?string $file = null, ? */ public static function cleanPath(string $file): string { - switch (true) { - case strpos($file, APPPATH) === 0: - $file = 'APPPATH' . DIRECTORY_SEPARATOR . substr($file, strlen(APPPATH)); - break; - - case strpos($file, SYSTEMPATH) === 0: - $file = 'SYSTEMPATH' . DIRECTORY_SEPARATOR . substr($file, strlen(SYSTEMPATH)); - break; - - case strpos($file, FCPATH) === 0: - $file = 'FCPATH' . DIRECTORY_SEPARATOR . substr($file, strlen(FCPATH)); - break; - - case defined('VENDORPATH') && strpos($file, VENDORPATH) === 0: - $file = 'VENDORPATH' . DIRECTORY_SEPARATOR . substr($file, strlen(VENDORPATH)); - break; - } - - return $file; + return match (true) { + str_starts_with($file, APPPATH) => 'APPPATH' . DIRECTORY_SEPARATOR . substr($file, strlen(APPPATH)), + str_starts_with($file, SYSTEMPATH) => 'SYSTEMPATH' . DIRECTORY_SEPARATOR . substr($file, strlen(SYSTEMPATH)), + str_starts_with($file, FCPATH) => 'FCPATH' . DIRECTORY_SEPARATOR . substr($file, strlen(FCPATH)), + defined('VENDORPATH') && str_starts_with($file, VENDORPATH) => 'VENDORPATH' . DIRECTORY_SEPARATOR . substr($file, strlen(VENDORPATH)), + default => $file, + }; } /** @@ -542,7 +530,7 @@ public static function highlightFile(string $file, int $lineNumber, int $lines = try { $source = file_get_contents($file); - } catch (Throwable $e) { + } catch (Throwable) { return false; } @@ -607,23 +595,12 @@ private static function renderBacktrace(array $backtrace): string $idx = $index; $idx = str_pad((string) ++$idx, 2, ' ', STR_PAD_LEFT); - $args = implode(', ', array_map(static function ($value): string { - switch (true) { - case is_object($value): - return sprintf('Object(%s)', get_class($value)); - - case is_array($value): - return $value !== [] ? '[...]' : '[]'; - - case $value === null: - return 'null'; - - case is_resource($value): - return sprintf('resource (%s)', get_resource_type($value)); - - default: - return var_export($value, true); - } + $args = implode(', ', array_map(static fn ($value): string => match (true) { + is_object($value) => sprintf('Object(%s)', $value::class), + is_array($value) => $value !== [] ? '[...]' : '[]', + $value === null => 'null', + is_resource($value) => sprintf('resource (%s)', get_resource_type($value)), + default => var_export($value, true), }, $frame['args'])); $backtraces[] = sprintf( diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 3f846a36d2e7..ff878785ccd2 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -326,7 +326,7 @@ protected function structureTimelineData(array $elements): array } // Make sure our younger siblings know their relatives, too - return array_merge([$element], $this->structureTimelineData($elements)); + return [$element, ...$this->structureTimelineData($elements)]; } /** @@ -408,7 +408,7 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r // Non-HTML formats should not include the debugbar // then we send headers saying where to find the debug data // for this response - if ($request->isAJAX() || strpos($format, 'html') === false) { + if ($request->isAJAX() || ! str_contains($format, 'html')) { $response->setHeader('Debugbar-Time', "{$time}") ->setHeader('Debugbar-Link', site_url("?debugbar_time={$time}")); @@ -431,7 +431,7 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r . $kintScript . PHP_EOL; - if (strpos($response->getBody(), '') !== false) { + if (str_contains($response->getBody(), '')) { $response->setBody( preg_replace( '//', diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index b527f2ed3c95..93178f95d9c2 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -161,7 +161,7 @@ public function display(): array } // find the first trace line that does not originate from `system/` - if ($firstNonSystemLine === '' && strpos($line['file'], 'SYSTEMPATH') === false) { + if ($firstNonSystemLine === '' && ! str_contains($line['file'], 'SYSTEMPATH')) { $firstNonSystemLine = $line['file']; } diff --git a/system/Debug/Toolbar/Collectors/Files.php b/system/Debug/Toolbar/Collectors/Files.php index c281906cdd28..4461b4b667d8 100644 --- a/system/Debug/Toolbar/Collectors/Files.php +++ b/system/Debug/Toolbar/Collectors/Files.php @@ -60,7 +60,7 @@ public function display(): array foreach ($rawFiles as $file) { $path = clean_path($file); - if (strpos($path, 'SYSTEMPATH') !== false) { + if (str_contains($path, 'SYSTEMPATH')) { $coreFiles[] = [ 'path' => $path, 'name' => basename($file), diff --git a/system/Debug/Toolbar/Collectors/Routes.php b/system/Debug/Toolbar/Collectors/Routes.php index 46aa91644004..c80ef7948fdf 100644 --- a/system/Debug/Toolbar/Collectors/Routes.php +++ b/system/Debug/Toolbar/Collectors/Routes.php @@ -63,7 +63,7 @@ public function display(): array } else { try { $method = new ReflectionMethod($router->controllerName(), $router->methodName()); - } catch (ReflectionException $e) { + } catch (ReflectionException) { try { // If we're here, the method doesn't exist // and is likely calculated in _remap. diff --git a/system/Email/Email.php b/system/Email/Email.php index 27e5bc83b683..c3d56033b6d1 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -658,7 +658,7 @@ public function setMessage($body) public function attach($file, $disposition = '', $newname = null, $mime = '') { if ($mime === '') { - if (strpos($file, '://') === false && ! is_file($file)) { + if (! str_contains($file, '://') && ! is_file($file)) { $this->setErrorMessage(lang('Email.attachmentMissing', [$file])); return false; @@ -738,7 +738,7 @@ public function setHeader($header, $value) protected function stringToArray($email) { if (! is_array($email)) { - return (strpos($email, ',') !== false) ? preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY) : (array) trim($email); + return (str_contains($email, ',')) ? preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY) : (array) trim($email); } return $email; @@ -862,7 +862,7 @@ protected function getEncoding() } foreach ($this->baseCharsets as $charset) { - if (strpos($this->charset, $charset) === 0) { + if (str_starts_with($this->charset, $charset)) { $this->encoding = '7bit'; break; @@ -1011,7 +1011,7 @@ public function wordWrap($str, $charlim = null) $charlim = empty($this->wrapChars) ? 76 : $this->wrapChars; } - if (strpos($str, "\r") !== false) { + if (str_contains($str, "\r")) { $str = str_replace(["\r\n", "\r"], "\n", $str); } @@ -1409,7 +1409,7 @@ protected function prepQuotedPrintable($str) $str = preg_replace(['| +|', '/\x00+/'], [' ', ''], $str); // Standardize newlines - if (strpos($str, "\r") !== false) { + if (str_contains($str, "\r")) { $str = str_replace(["\r\n", "\r"], "\n", $str); } @@ -1644,10 +1644,7 @@ protected function unwrapSpecials() { $this->finalBody = preg_replace_callback( '/\{unwrap\}(.*?)\{\/unwrap\}/si', - [ - $this, - 'removeNLCallback', - ], + $this->removeNLCallback(...), $this->finalBody ); } @@ -1655,13 +1652,13 @@ protected function unwrapSpecials() /** * Strip line-breaks via callback * - * @param string $matches + * @param array $matches * * @return string */ protected function removeNLCallback($matches) { - if (strpos($matches[1], "\r") !== false || strpos($matches[1], "\n") !== false) { + if (str_contains($matches[1], "\r") || str_contains($matches[1], "\n")) { $matches[1] = str_replace(["\r\n", "\r", "\n"], '', $matches[1]); } @@ -1842,7 +1839,7 @@ protected function sendWithSmtp() $this->setErrorMessage($reply); $this->SMTPEnd(); - if (strpos($reply, '250') !== 0) { + if (! str_starts_with($reply, '250')) { $this->setErrorMessage(lang('Email.SMTPError', [$reply])); return false; @@ -2014,11 +2011,11 @@ protected function SMTPAuthenticate() $this->sendData('AUTH LOGIN'); $reply = $this->getSMTPData(); - if (strpos($reply, '503') === 0) { // Already authenticated + if (str_starts_with($reply, '503')) { // Already authenticated return true; } - if (strpos($reply, '334') !== 0) { + if (! str_starts_with($reply, '334')) { $this->setErrorMessage(lang('Email.failedSMTPLogin', [$reply])); return false; @@ -2027,7 +2024,7 @@ protected function SMTPAuthenticate() $this->sendData(base64_encode($this->SMTPUser)); $reply = $this->getSMTPData(); - if (strpos($reply, '334') !== 0) { + if (! str_starts_with($reply, '334')) { $this->setErrorMessage(lang('Email.SMTPAuthUsername', [$reply])); return false; @@ -2036,7 +2033,7 @@ protected function SMTPAuthenticate() $this->sendData(base64_encode($this->SMTPPass)); $reply = $this->getSMTPData(); - if (strpos($reply, '235') !== 0) { + if (! str_starts_with($reply, '235')) { $this->setErrorMessage(lang('Email.SMTPAuthPassword', [$reply])); return false; @@ -2252,7 +2249,7 @@ protected static function substr($str, $start, $length = null) protected function setArchiveValues(): array { // Get property values and add anything prepped in tmpArchive - $this->archive = array_merge(get_object_vars($this), $this->tmpArchive); + $this->archive = [...get_object_vars($this), ...$this->tmpArchive]; unset($this->archive['archive']); // Clear tmpArchive for next run diff --git a/system/Entity/Cast/ArrayCast.php b/system/Entity/Cast/ArrayCast.php index 315f2e582fec..d68d17c187de 100644 --- a/system/Entity/Cast/ArrayCast.php +++ b/system/Entity/Cast/ArrayCast.php @@ -21,7 +21,7 @@ class ArrayCast extends BaseCast */ public static function get($value, array $params = []): array { - if (is_string($value) && (strpos($value, 'a:') === 0 || strpos($value, 's:') === 0)) { + if (is_string($value) && (str_starts_with($value, 'a:') || str_starts_with($value, 's:'))) { $value = unserialize($value); } diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 90d3ab46a297..32c2393836dd 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -167,7 +167,7 @@ public function toArray(bool $onlyChanged = false, bool $cast = true, bool $recu { $this->_cast = $cast; - $keys = array_filter(array_keys($this->attributes), static fn ($key) => strpos($key, '_') !== 0); + $keys = array_filter(array_keys($this->attributes), static fn ($key) => ! str_starts_with($key, '_')); if (is_array($this->datamap)) { $keys = array_unique( @@ -368,7 +368,7 @@ protected function castAs($value, string $attribute, string $method = 'get') $isNullable = false; - if (strpos($type, '?') === 0) { + if (str_starts_with($type, '?')) { $isNullable = true; if ($value === null) { @@ -401,7 +401,7 @@ protected function castAs($value, string $attribute, string $method = 'get') $type = trim($type, '[]'); - $handlers = array_merge($this->defaultCastHandlers, $this->castHandlers); + $handlers = [...$this->defaultCastHandlers, ...$this->castHandlers]; if (empty($handlers[$type])) { return $value; diff --git a/system/Entity/Exceptions/CastException.php b/system/Entity/Exceptions/CastException.php index e259447b3f76..4bcb62be8067 100644 --- a/system/Entity/Exceptions/CastException.php +++ b/system/Entity/Exceptions/CastException.php @@ -41,25 +41,14 @@ public static function forInvalidInterface(string $class) */ public static function forInvalidJsonFormat(int $error) { - switch ($error) { - case JSON_ERROR_DEPTH: - return new static(lang('Cast.jsonErrorDepth')); - - case JSON_ERROR_STATE_MISMATCH: - return new static(lang('Cast.jsonErrorStateMismatch')); - - case JSON_ERROR_CTRL_CHAR: - return new static(lang('Cast.jsonErrorCtrlChar')); - - case JSON_ERROR_SYNTAX: - return new static(lang('Cast.jsonErrorSyntax')); - - case JSON_ERROR_UTF8: - return new static(lang('Cast.jsonErrorUtf8')); - - default: - return new static(lang('Cast.jsonErrorUnknown')); - } + return match ($error) { + JSON_ERROR_DEPTH => new static(lang('Cast.jsonErrorDepth')), + JSON_ERROR_STATE_MISMATCH => new static(lang('Cast.jsonErrorStateMismatch')), + JSON_ERROR_CTRL_CHAR => new static(lang('Cast.jsonErrorCtrlChar')), + JSON_ERROR_SYNTAX => new static(lang('Cast.jsonErrorSyntax')), + JSON_ERROR_UTF8 => new static(lang('Cast.jsonErrorUtf8')), + default => new static(lang('Cast.jsonErrorUnknown')), + }; } /** diff --git a/system/Events/Events.php b/system/Events/Events.php index b240dc29e1ca..fa10e8b4be14 100644 --- a/system/Events/Events.php +++ b/system/Events/Events.php @@ -91,7 +91,7 @@ public static function initialize() return false; // @codeCoverageIgnore }, $files)); - static::$files = array_unique(array_merge($files, [$events])); + static::$files = array_unique([...$files, $events]); foreach (static::$files as $file) { include $file; diff --git a/system/Exceptions/CastException.php b/system/Exceptions/CastException.php index 8dfb29543a78..e316f8726d9a 100644 --- a/system/Exceptions/CastException.php +++ b/system/Exceptions/CastException.php @@ -32,24 +32,13 @@ public function getExitCode(): int */ public static function forInvalidJsonFormatException(int $error) { - switch ($error) { - case JSON_ERROR_DEPTH: - return new static(lang('Cast.jsonErrorDepth')); - - case JSON_ERROR_STATE_MISMATCH: - return new static(lang('Cast.jsonErrorStateMismatch')); - - case JSON_ERROR_CTRL_CHAR: - return new static(lang('Cast.jsonErrorCtrlChar')); - - case JSON_ERROR_SYNTAX: - return new static(lang('Cast.jsonErrorSyntax')); - - case JSON_ERROR_UTF8: - return new static(lang('Cast.jsonErrorUtf8')); - - default: - return new static(lang('Cast.jsonErrorUnknown')); - } + return match ($error) { + JSON_ERROR_DEPTH => new static(lang('Cast.jsonErrorDepth')), + JSON_ERROR_STATE_MISMATCH => new static(lang('Cast.jsonErrorStateMismatch')), + JSON_ERROR_CTRL_CHAR => new static(lang('Cast.jsonErrorCtrlChar')), + JSON_ERROR_SYNTAX => new static(lang('Cast.jsonErrorSyntax')), + JSON_ERROR_UTF8 => new static(lang('Cast.jsonErrorUtf8')), + default => new static(lang('Cast.jsonErrorUnknown')), + }; } } diff --git a/system/Exceptions/FrameworkException.php b/system/Exceptions/FrameworkException.php index faf3f1480126..83f9cb2808b6 100644 --- a/system/Exceptions/FrameworkException.php +++ b/system/Exceptions/FrameworkException.php @@ -60,7 +60,7 @@ public static function forCopyError(string $path) */ public static function forMissingExtension(string $extension) { - if (strpos($extension, 'intl') !== false) { + if (str_contains($extension, 'intl')) { // @codeCoverageIgnoreStart $message = sprintf( 'The framework needs the following extension(s) installed and loaded: %s.', diff --git a/system/Files/File.php b/system/Files/File.php index 4e4ee388047e..d0842fb6bb7a 100644 --- a/system/Files/File.php +++ b/system/Files/File.php @@ -74,16 +74,11 @@ public function getSize() */ public function getSizeByUnit(string $unit = 'b') { - switch (strtolower($unit)) { - case 'kb': - return number_format($this->getSize() / 1024, 3); - - case 'mb': - return number_format(($this->getSize() / 1024) / 1024, 3); - - default: - return $this->getSize(); - } + return match (strtolower($unit)) { + 'kb' => number_format($this->getSize() / 1024, 3), + 'mb' => number_format(($this->getSize() / 1024) / 1024, 3), + default => $this->getSize(), + }; } /** @@ -173,7 +168,7 @@ public function getDestination(string $destination, string $delimiter = '_', int $info = pathinfo($destination); $extension = isset($info['extension']) ? '.' . $info['extension'] : ''; - if (strpos($info['filename'], $delimiter) !== false) { + if (str_contains($info['filename'], $delimiter)) { $parts = explode($delimiter, $info['filename']); if (is_numeric(end($parts))) { diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php index 87f987eb8f1e..545f8997a3b0 100644 --- a/system/Files/FileCollection.php +++ b/system/Files/FileCollection.php @@ -83,7 +83,7 @@ final protected static function filterFiles(array $files, string $directory): ar { $directory = self::resolveDirectory($directory); - return array_filter($files, static fn (string $value): bool => strpos($value, $directory) === 0); + return array_filter($files, static fn (string $value): bool => str_starts_with($value, $directory)); } /** @@ -180,7 +180,7 @@ public function add($paths, bool $recursive = true) try { // Test for a directory self::resolveDirectory($path); - } catch (FileException $e) { + } catch (FileException) { $this->addFile($path); continue; diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index 25ca9a9ec5f7..acfc9970c522 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -192,7 +192,7 @@ private function runBefore(array $filterClasses) $class = new $className(); if (! $class instanceof FilterInterface) { - throw FilterException::forIncorrectInterface(get_class($class)); + throw FilterException::forIncorrectInterface($class::class); } $result = $class->before( @@ -230,7 +230,7 @@ private function runAfter(array $filterClasses): ResponseInterface $class = new $className(); if (! $class instanceof FilterInterface) { - throw FilterException::forIncorrectInterface(get_class($class)); + throw FilterException::forIncorrectInterface($class::class); } $result = $class->after( @@ -485,7 +485,7 @@ private function getCleanName(string $name): array { $arguments = []; - if (strpos($name, ':') !== false) { + if (str_contains($name, ':')) { [$name, $arguments] = explode(':', $name); $arguments = explode(',', $arguments); diff --git a/system/Filters/InvalidChars.php b/system/Filters/InvalidChars.php index 93124fdb4e9f..0bddd4862252 100644 --- a/system/Filters/InvalidChars.php +++ b/system/Filters/InvalidChars.php @@ -90,7 +90,7 @@ public function after(RequestInterface $request, ResponseInterface $response, $a protected function checkEncoding($value) { if (is_array($value)) { - array_map([$this, 'checkEncoding'], $value); + array_map($this->checkEncoding(...), $value); return $value; } @@ -112,7 +112,7 @@ protected function checkEncoding($value) protected function checkControl($value) { if (is_array($value)) { - array_map([$this, 'checkControl'], $value); + array_map($this->checkControl(...), $value); return $value; } diff --git a/system/Filters/PageCache.php b/system/Filters/PageCache.php index d6fa407f5a0d..c3bb2af90dd6 100644 --- a/system/Filters/PageCache.php +++ b/system/Filters/PageCache.php @@ -25,7 +25,7 @@ */ class PageCache implements FilterInterface { - private ResponseCache $pageCache; + private readonly ResponseCache $pageCache; public function __construct() { diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 35b62ec3486f..8ee1cb7cb920 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -89,7 +89,7 @@ class CURLRequest extends OutgoingRequest /** * The default options from the constructor. Applied to all requests. */ - private array $defaultOptions; + private readonly array $defaultOptions; /** * Whether share options between requests or not. @@ -97,7 +97,7 @@ class CURLRequest extends OutgoingRequest * If true, all the options won't be reset between requests. * It may cause an error request with unnecessary headers. */ - private bool $shareOptions; + private readonly bool $shareOptions; /** * Takes an array of options to set the following possible class properties: @@ -323,7 +323,7 @@ protected function parseOptions(array $options) protected function prepareURL(string $url): string { // If it's a full URI, then we have nothing to do here... - if (strpos($url, '://') !== false) { + if (str_contains($url, '://')) { return $url; } @@ -378,16 +378,16 @@ public function send(string $method, string $url) // Set the string we want to break our response from $breakString = "\r\n\r\n"; - if (strpos($output, 'HTTP/1.1 100 Continue') === 0) { + if (str_starts_with($output, 'HTTP/1.1 100 Continue')) { $output = substr($output, strpos($output, $breakString) + 4); } - if (strpos($output, 'HTTP/1.1 200 Connection established') === 0) { + if (str_starts_with($output, 'HTTP/1.1 200 Connection established')) { $output = substr($output, strpos($output, $breakString) + 4); } // If request and response have Digest - if (isset($this->config['auth'][2]) && $this->config['auth'][2] === 'digest' && strpos($output, 'WWW-Authenticate: Digest') !== false) { + if (isset($this->config['auth'][2]) && $this->config['auth'][2] === 'digest' && str_contains($output, 'WWW-Authenticate: Digest')) { $output = substr($output, strpos($output, $breakString) + 4); } @@ -487,7 +487,7 @@ protected function setResponseHeaders(array $headers = []) } else { $this->response->setHeader($title, $value); } - } elseif (strpos($header, 'HTTP') === 0) { + } elseif (str_starts_with($header, 'HTTP')) { preg_match('#^HTTP\/([12](?:\.[01])?) (\d+) (.+)#', $header, $matches); if (isset($matches[1])) { diff --git a/system/HTTP/ContentSecurityPolicy.php b/system/HTTP/ContentSecurityPolicy.php index 6a3caed925b8..82ee286716e7 100644 --- a/system/HTTP/ContentSecurityPolicy.php +++ b/system/HTTP/ContentSecurityPolicy.php @@ -800,7 +800,7 @@ protected function addToHeader(string $name, $values = null) $reportOnly = $this->reportOnly; } - if (strpos($value, 'nonce-') === 0) { + if (str_starts_with($value, 'nonce-')) { $value = "'{$value}'"; } diff --git a/system/HTTP/DownloadResponse.php b/system/HTTP/DownloadResponse.php index 14dc3fec1421..fc077f1a251e 100644 --- a/system/HTTP/DownloadResponse.php +++ b/system/HTTP/DownloadResponse.php @@ -36,7 +36,7 @@ class DownloadResponse extends Response /** * mime set flag */ - private bool $setMime; + private readonly bool $setMime; /** * Download for binary diff --git a/system/HTTP/Files/FileCollection.php b/system/HTTP/Files/FileCollection.php index 7188d357b006..6de5f2d0f80d 100644 --- a/system/HTTP/Files/FileCollection.php +++ b/system/HTTP/Files/FileCollection.php @@ -57,7 +57,7 @@ public function getFile(string $name) $this->populateFiles(); if ($this->hasFile($name)) { - if (strpos($name, '.') !== false) { + if (str_contains($name, '.')) { $name = explode('.', $name); $uploadedFile = $this->getValueDotNotationSyntax($name, $this->files); @@ -84,7 +84,7 @@ public function getFileMultiple(string $name) $this->populateFiles(); if ($this->hasFile($name)) { - if (strpos($name, '.') !== false) { + if (str_contains($name, '.')) { $name = explode('.', $name); $uploadedFile = $this->getValueDotNotationSyntax($name, $this->files); @@ -113,7 +113,7 @@ public function hasFile(string $fileID): bool { $this->populateFiles(); - if (strpos($fileID, '.') !== false) { + if (str_contains($fileID, '.')) { $segments = explode('.', $fileID); $el = $this->files; diff --git a/system/HTTP/Files/UploadedFile.php b/system/HTTP/Files/UploadedFile.php index 70ece748d834..b81881c62cb3 100644 --- a/system/HTTP/Files/UploadedFile.php +++ b/system/HTTP/Files/UploadedFile.php @@ -151,7 +151,7 @@ public function move(string $targetPath, ?string $name = null, bool $overwrite = try { $this->hasMoved = move_uploaded_file($this->path, $destination); - } catch (Exception $e) { + } catch (Exception) { $error = error_get_last(); $message = strip_tags($error['message'] ?? ''); diff --git a/system/HTTP/Header.php b/system/HTTP/Header.php index b152509a1cee..0c27e65dbb33 100644 --- a/system/HTTP/Header.php +++ b/system/HTTP/Header.php @@ -11,6 +11,8 @@ namespace CodeIgniter\HTTP; +use Stringable; + /** * Class Header * @@ -18,7 +20,7 @@ * * @see \CodeIgniter\HTTP\HeaderTest */ -class Header +class Header implements Stringable { /** * The name of the header. diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index ee5aa8bd6ca0..be1342a9e94c 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -158,7 +158,7 @@ public function __construct($config, ?URI $uri = null, $body = 'php://input', ?U $body === 'php://input' // php://input is not available with enctype="multipart/form-data". // See https://www.php.net/manual/en/wrappers.php.php#wrappers.php.input - && strpos($this->getHeaderLine('Content-Type'), 'multipart/form-data') === false + && ! str_contains($this->getHeaderLine('Content-Type'), 'multipart/form-data') && (int) $this->getHeaderLine('Content-Length') <= $this->getPostMaxSize() ) { // Get our body from php://input @@ -191,24 +191,12 @@ private function getPostMaxSize(): int { $postMaxSize = ini_get('post_max_size'); - switch (strtoupper(substr($postMaxSize, -1))) { - case 'G': - $postMaxSize = (int) str_replace('G', '', $postMaxSize) * 1024 ** 3; - break; - - case 'M': - $postMaxSize = (int) str_replace('M', '', $postMaxSize) * 1024 ** 2; - break; - - case 'K': - $postMaxSize = (int) str_replace('K', '', $postMaxSize) * 1024; - break; - - default: - $postMaxSize = (int) $postMaxSize; - } - - return $postMaxSize; + return match (strtoupper(substr($postMaxSize, -1))) { + 'G' => (int) str_replace('G', '', $postMaxSize) * 1024 ** 3, + 'M' => (int) str_replace('M', '', $postMaxSize) * 1024 ** 2, + 'K' => (int) str_replace('K', '', $postMaxSize) * 1024, + default => (int) $postMaxSize, + }; } /** @@ -256,20 +244,11 @@ public function detectPath(string $protocol = ''): string $protocol = 'REQUEST_URI'; } - switch ($protocol) { - case 'REQUEST_URI': - $this->path = $this->parseRequestURI(); - break; - - case 'QUERY_STRING': - $this->path = $this->parseQueryString(); - break; - - case 'PATH_INFO': - default: - $this->path = $this->fetchGlobal('server', $protocol) ?? $this->parseRequestURI(); - break; - } + $this->path = match ($protocol) { + 'REQUEST_URI' => $this->parseRequestURI(), + 'QUERY_STRING' => $this->parseQueryString(), + default => $this->fetchGlobal('server', $protocol) ?? $this->parseRequestURI(), + }; return $this->path; } @@ -317,7 +296,7 @@ protected function parseRequestURI(): string // This section ensures that even on servers that require the URI to contain the query string (Nginx) a correct // URI is found, and also fixes the QUERY_STRING Server var and $_GET array. - if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 0) { + if (trim($uri, '/') === '' && str_starts_with($query, '/')) { $query = explode('?', $query, 2); $uri = $query[0]; $_SERVER['QUERY_STRING'] = $query[1] ?? ''; @@ -350,7 +329,7 @@ protected function parseQueryString(): string return '/'; } - if (strncmp($uri, '/', 1) === 0) { + if (str_starts_with($uri, '/')) { $uri = explode('?', $uri, 2); $_SERVER['QUERY_STRING'] = $uri[1] ?? ''; $uri = $uri[0]; @@ -376,21 +355,13 @@ public function negotiate(string $type, array $supported, bool $strictMatch = fa $this->negotiator = Services::negotiator($this, true); } - switch (strtolower($type)) { - case 'media': - return $this->negotiator->media($supported, $strictMatch); - - case 'charset': - return $this->negotiator->charset($supported); - - case 'encoding': - return $this->negotiator->encoding($supported); - - case 'language': - return $this->negotiator->language($supported); - } - - throw HTTPException::forInvalidNegotiationType($type); + return match (strtolower($type)) { + 'media' => $this->negotiator->media($supported, $strictMatch), + 'charset' => $this->negotiator->charset($supported), + 'encoding' => $this->negotiator->encoding($supported), + 'language' => $this->negotiator->language($supported), + default => throw HTTPException::forInvalidNegotiationType($type), + }; } /** @@ -410,7 +381,7 @@ public function is(string $type): bool } if ($valueUpper === 'JSON') { - return strpos($this->getHeaderLine('Content-Type'), 'application/json') !== false; + return str_contains($this->getHeaderLine('Content-Type'), 'application/json'); } if ($valueUpper === 'AJAX') { @@ -546,7 +517,7 @@ public function getDefaultLocale(): string public function getVar($index = null, $filter = null, $flags = null) { if ( - strpos($this->getHeaderLine('Content-Type'), 'application/json') !== false + str_contains($this->getHeaderLine('Content-Type'), 'application/json') && $this->body !== null ) { return $this->getJsonVar($index, false, $filter, $flags); diff --git a/system/HTTP/Method.php b/system/HTTP/Method.php index 7aae162b3cba..6ad3847cc2f7 100644 --- a/system/HTTP/Method.php +++ b/system/HTTP/Method.php @@ -19,59 +19,59 @@ class Method /** * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT */ - public const CONNECT = 'CONNECT'; + final public const CONNECT = 'CONNECT'; /** * Idempotent * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE */ - public const DELETE = 'DELETE'; + final public const DELETE = 'DELETE'; /** * Safe, Idempotent, Cacheable * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET */ - public const GET = 'GET'; + final public const GET = 'GET'; /** * Safe, Idempotent, Cacheable * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD */ - public const HEAD = 'HEAD'; + final public const HEAD = 'HEAD'; /** * Safe, Idempotent * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS */ - public const OPTIONS = 'OPTIONS'; + final public const OPTIONS = 'OPTIONS'; /** * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH */ - public const PATCH = 'PATCH'; + final public const PATCH = 'PATCH'; /** * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST */ - public const POST = 'POST'; + final public const POST = 'POST'; /** * Idempotent * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT */ - public const PUT = 'PUT'; + final public const PUT = 'PUT'; /** * Safe, Idempotent * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/TRACE */ - public const TRACE = 'TRACE'; + final public const TRACE = 'TRACE'; /** * Returns all HTTP methods. diff --git a/system/HTTP/RedirectResponse.php b/system/HTTP/RedirectResponse.php index 8efd4c2c51ea..9c406df504cf 100644 --- a/system/HTTP/RedirectResponse.php +++ b/system/HTTP/RedirectResponse.php @@ -35,7 +35,7 @@ public function to(string $uri, ?int $code = null, string $method = 'auto') { // If it appears to be a relative URL, then convert to full URL // for better security. - if (strpos($uri, 'http') !== 0) { + if (! str_starts_with($uri, 'http')) { $uri = site_url($uri); } diff --git a/system/HTTP/RequestTrait.php b/system/HTTP/RequestTrait.php index 6db903ddacec..5609d786b23f 100644 --- a/system/HTTP/RequestTrait.php +++ b/system/HTTP/RequestTrait.php @@ -77,7 +77,7 @@ public function getIPAddress(): string // @TODO Extract all this IP address logic to another class. foreach ($proxyIPs as $proxyIP => $header) { // Check if we have an IP address or a subnet - if (strpos($proxyIP, '/') === false) { + if (! str_contains($proxyIP, '/')) { // An IP address (and not a subnet) is specified. // We can compare right away. if ($proxyIP === $this->ipAddress) { @@ -98,7 +98,7 @@ public function getIPAddress(): string } // If the proxy entry doesn't match the IP protocol - skip it - if (strpos($proxyIP, $separator) === false) { + if (! str_contains($proxyIP, $separator)) { continue; } diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index e5e006c776aa..e93d4279a428 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -447,7 +447,7 @@ public function redirect(string $uri, string $method = 'auto', ?int $code = null if ( $method === 'auto' && isset($_SERVER['SERVER_SOFTWARE']) - && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false + && str_contains($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') ) { $method = 'refresh'; } elseif ($method !== 'refresh' && $code === null) { @@ -471,15 +471,10 @@ public function redirect(string $uri, string $method = 'auto', ?int $code = null $code = 302; } - switch ($method) { - case 'refresh': - $this->setHeader('Refresh', '0;url=' . $uri); - break; - - default: - $this->setHeader('Location', $uri); - break; - } + match ($method) { + 'refresh' => $this->setHeader('Refresh', '0;url=' . $uri), + default => $this->setHeader('Location', $uri), + }; $this->setStatusCode($code); diff --git a/system/HTTP/SiteURI.php b/system/HTTP/SiteURI.php index 6d56507314e7..853a2166edab 100644 --- a/system/HTTP/SiteURI.php +++ b/system/HTTP/SiteURI.php @@ -15,18 +15,19 @@ use CodeIgniter\Exceptions\ConfigException; use CodeIgniter\HTTP\Exceptions\HTTPException; use Config\App; +use Stringable; /** * URI for the application site * * @see \CodeIgniter\HTTP\SiteURITest */ -class SiteURI extends URI +class SiteURI extends URI implements Stringable { /** * The current baseURL. */ - private URI $baseURL; + private readonly URI $baseURL; /** * The path part of baseURL. diff --git a/system/HTTP/SiteURIFactory.php b/system/HTTP/SiteURIFactory.php index 36b9d705b28c..d1391baf597f 100644 --- a/system/HTTP/SiteURIFactory.php +++ b/system/HTTP/SiteURIFactory.php @@ -24,13 +24,10 @@ */ final class SiteURIFactory { - private App $appConfig; - private Superglobals $superglobals; - - public function __construct(App $appConfig, Superglobals $superglobals) - { - $this->appConfig = $appConfig; - $this->superglobals = $superglobals; + public function __construct( + private readonly App $appConfig, + private readonly Superglobals $superglobals + ) { } /** @@ -95,20 +92,11 @@ public function detectRoutePath(string $protocol = ''): string $protocol = $this->appConfig->uriProtocol; } - switch ($protocol) { - case 'REQUEST_URI': - $routePath = $this->parseRequestURI(); - break; - - case 'QUERY_STRING': - $routePath = $this->parseQueryString(); - break; - - case 'PATH_INFO': - default: - $routePath = $this->superglobals->server($protocol) ?? $this->parseRequestURI(); - break; - } + $routePath = match ($protocol) { + 'REQUEST_URI' => $this->parseRequestURI(), + 'QUERY_STRING' => $this->parseQueryString(), + default => $this->superglobals->server($protocol) ?? $this->parseRequestURI(), + }; return ($routePath === '/' || $routePath === '') ? '/' : ltrim($routePath, '/'); } @@ -161,7 +149,7 @@ private function parseRequestURI(): string // This section ensures that even on servers that require the URI to // contain the query string (Nginx) a correct URI is found, and also // fixes the QUERY_STRING Server var and $_GET array. - if (trim($path, '/') === '' && strncmp($query, '/', 1) === 0) { + if (trim($path, '/') === '' && str_starts_with($query, '/')) { $parts = explode('?', $query, 2); $path = $parts[0]; $newQuery = $query[1] ?? ''; @@ -193,7 +181,7 @@ private function parseQueryString(): string return '/'; } - if (strncmp($query, '/', 1) === 0) { + if (str_starts_with($query, '/')) { $parts = explode('?', $query, 2); $path = $parts[0]; $newQuery = $parts[1] ?? ''; diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index 608f8b75d5ba..7d1913da8229 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -15,13 +15,14 @@ use CodeIgniter\HTTP\Exceptions\HTTPException; use Config\App; use InvalidArgumentException; +use Stringable; /** * Abstraction for a uniform resource identifier (URI). * * @see \CodeIgniter\HTTP\URITest */ -class URI +class URI implements Stringable { /** * Sub-delimiters used in query strings and fragments. @@ -172,7 +173,7 @@ public static function createURIString( } if (isset($path) && $path !== '') { - $uri .= substr($uri, -1, 1) !== '/' + $uri .= ! str_ends_with($uri, '/') ? '/' . ltrim($path, '/') : ltrim($path, '/'); } @@ -228,12 +229,12 @@ public static function removeDotSegments(string $path): string $output = trim($output, '/ '); // Add leading slash if necessary - if (strpos($path, '/') === 0) { + if (str_starts_with($path, '/')) { $output = '/' . $output; } // Add trailing slash if necessary - if ($output !== '/' && substr($path, -1, 1) === '/') { + if ($output !== '/' && str_ends_with($path, '/')) { $output .= '/'; } @@ -652,14 +653,14 @@ private function changeSchemeAndPath(string $scheme, string $path): array $baseUri = new self($config->baseURL); if ( - substr($this->getScheme(), 0, 4) === 'http' + str_starts_with($this->getScheme(), 'http') && $this->getHost() === $baseUri->getHost() ) { // Check for additional segments $basePath = trim($baseUri->getPath(), '/') . '/'; $trimPath = ltrim($path, '/'); - if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0) { + if ($basePath !== '/' && ! str_starts_with($trimPath, $basePath)) { $path = $basePath . $trimPath; } @@ -877,7 +878,7 @@ public function refreshPath() */ public function setQuery(string $query) { - if (strpos($query, '#') !== false) { + if (str_contains($query, '#')) { if ($this->silent) { return $this; } @@ -886,7 +887,7 @@ public function setQuery(string $query) } // Can't have leading ? - if (! empty($query) && strpos($query, '?') === 0) { + if (! empty($query) && str_starts_with($query, '?')) { $query = substr($query, 1); } @@ -1008,10 +1009,10 @@ protected function filterPath(?string $path = null): string $path = self::removeDotSegments($path); // Fix up some leading slash edge cases... - if (strpos($orig, './') === 0) { + if (str_starts_with($orig, './')) { $path = '/' . $path; } - if (strpos($orig, '../') === 0) { + if (str_starts_with($orig, '../')) { $path = '/' . $path; } @@ -1112,7 +1113,7 @@ public function resolveRelativeURI(string $uri) $transformed->setQuery($this->getQuery()); } } else { - if (strpos($relative->getPath(), '/') === 0) { + if (str_starts_with($relative->getPath(), '/')) { $transformed->setPath($relative->getPath()); } else { $transformed->setPath($this->mergePaths($this, $relative)); diff --git a/system/HTTP/UserAgent.php b/system/HTTP/UserAgent.php index 77e7cb4392fc..4461ddc9db93 100644 --- a/system/HTTP/UserAgent.php +++ b/system/HTTP/UserAgent.php @@ -12,13 +12,14 @@ namespace CodeIgniter\HTTP; use Config\UserAgents; +use Stringable; /** * Abstraction for an HTTP user agent * * @see \CodeIgniter\HTTP\UserAgentTest */ -class UserAgent +class UserAgent implements Stringable { /** * Current user-agent diff --git a/system/Helpers/array_helper.php b/system/Helpers/array_helper.php index 6d501e273202..d11789a3e63a 100644 --- a/system/Helpers/array_helper.php +++ b/system/Helpers/array_helper.php @@ -136,7 +136,7 @@ function array_flatten_with_dots(iterable $array, string $id = ''): array $newKey = $id . $key; if (is_array($value) && $value !== []) { - $flattened = array_merge($flattened, array_flatten_with_dots($value, $newKey . '.')); + $flattened = [...$flattened, ...array_flatten_with_dots($value, $newKey . '.')]; } else { $flattened[$newKey] = $value; } diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index 47c829bbc3c6..cd46d7dc3721 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -53,7 +53,7 @@ function directory_map(string $sourceDir, int $directoryDepth = 0, bool $hidden closedir($fp); return $fileData; - } catch (Throwable $e) { + } catch (Throwable) { return []; } } @@ -129,7 +129,7 @@ function write_file(string $path, string $data, string $mode = 'wb'): bool fclose($fp); return is_int($result); - } catch (Throwable $e) { + } catch (Throwable) { return false; } } @@ -178,7 +178,7 @@ function delete_files(string $path, bool $delDir = false, bool $htdocs = false, } return true; - } catch (Throwable $e) { + } catch (Throwable) { return false; } } @@ -227,7 +227,7 @@ function get_filenames( } } } - } catch (Throwable $e) { + } catch (Throwable) { return []; } @@ -277,7 +277,7 @@ function get_dir_file_info(string $sourceDir, bool $topLevelOnly = true, bool $r closedir($fp); return $fileData; - } catch (Throwable $fe) { + } catch (Throwable) { return []; } } diff --git a/system/Helpers/form_helper.php b/system/Helpers/form_helper.php index 7edb05cf1de3..8a86cf690a1e 100644 --- a/system/Helpers/form_helper.php +++ b/system/Helpers/form_helper.php @@ -32,9 +32,9 @@ function form_open(string $action = '', $attributes = [], array $hidden = []): s if (! $action) { $action = current_url(true); } // If an action is not a full URL then turn it into one - elseif (strpos($action, '://') === false) { + elseif (! str_contains($action, '://')) { // If an action has {locale} - if (strpos($action, '{locale}') !== false) { + if (str_contains($action, '{locale}')) { $action = str_replace('{locale}', Services::request()->getLocale(), $action); } @@ -61,7 +61,7 @@ function form_open(string $action = '', $attributes = [], array $hidden = []): s // Add CSRF field if enabled, but leave it out for GET requests and requests to external websites $before = Services::filters()->getFilters()['before']; - if ((in_array('csrf', $before, true) || array_key_exists('csrf', $before)) && strpos($action, base_url()) !== false && ! stripos($form, 'method="get"')) { + if ((in_array('csrf', $before, true) || array_key_exists('csrf', $before)) && str_contains($action, base_url()) && ! stripos($form, 'method="get"')) { $form .= csrf_field($csrfId ?? null); } diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index 7a76434d0ea2..e43bf0b2a7d2 100755 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -108,7 +108,7 @@ function img($src = '', bool $indexPage = false, $attributes = ''): string $img = 'config->container) || strpos($this->config->container, '{template}') === false) { + if (empty($this->config->container) || ! str_contains($this->config->container, '{template}')) { $this->config->container = '
{template}
'; } diff --git a/system/Images/Handlers/BaseHandler.php b/system/Images/Handlers/BaseHandler.php index fef31755aaa3..ade0d5a455f6 100644 --- a/system/Images/Handlers/BaseHandler.php +++ b/system/Images/Handlers/BaseHandler.php @@ -413,7 +413,7 @@ abstract protected function _flip(string $direction); */ public function text(string $text, array $options = []) { - $options = array_merge($this->textDefaults, $options); + $options = [...$this->textDefaults, ...$options]; $options['color'] = trim($options['color'], '# '); $options['shadowColor'] = trim($options['shadowColor'], '# '); @@ -471,31 +471,16 @@ public function reorient(bool $silent = false) { $orientation = $this->getEXIF('Orientation', $silent); - switch ($orientation) { - case 2: - return $this->flip('horizontal'); - - case 3: - return $this->rotate(180); - - case 4: - return $this->rotate(180)->flip('horizontal'); - - case 5: - return $this->rotate(270)->flip('horizontal'); - - case 6: - return $this->rotate(270); - - case 7: - return $this->rotate(90)->flip('horizontal'); - - case 8: - return $this->rotate(90); - - default: - return $this; - } + return match ($orientation) { + 2 => $this->flip('horizontal'), + 3 => $this->rotate(180), + 4 => $this->rotate(180)->flip('horizontal'), + 5 => $this->rotate(270)->flip('horizontal'), + 6 => $this->rotate(270), + 7 => $this->rotate(90)->flip('horizontal'), + 8 => $this->rotate(90), + default => $this, + }; } /** diff --git a/system/Images/Handlers/ImageMagickHandler.php b/system/Images/Handlers/ImageMagickHandler.php index 857a273d5372..839a2e4790cc 100644 --- a/system/Images/Handlers/ImageMagickHandler.php +++ b/system/Images/Handlers/ImageMagickHandler.php @@ -448,30 +448,15 @@ public function reorient(bool $silent = false) { $orientation = $this->getEXIF('Orientation', $silent); - switch ($orientation) { - case 2: - return $this->flip('horizontal'); - - case 3: - return $this->rotate(180); - - case 4: - return $this->rotate(180)->flip('horizontal'); - - case 5: - return $this->rotate(90)->flip('horizontal'); - - case 6: - return $this->rotate(90); - - case 7: - return $this->rotate(270)->flip('horizontal'); - - case 8: - return $this->rotate(270); - - default: - return $this; - } + return match ($orientation) { + 2 => $this->flip('horizontal'), + 3 => $this->rotate(180), + 4 => $this->rotate(180)->flip('horizontal'), + 5 => $this->rotate(90)->flip('horizontal'), + 6 => $this->rotate(90), + 7 => $this->rotate(270)->flip('horizontal'), + 8 => $this->rotate(270), + default => $this, + }; } } diff --git a/system/Language/Language.php b/system/Language/Language.php index 8633f8a2dd9c..8c32a8214480 100644 --- a/system/Language/Language.php +++ b/system/Language/Language.php @@ -93,7 +93,7 @@ public function getLocale(): string public function getLine(string $line, array $args = []) { // if no file is given, just parse the line - if (strpos($line, '.') === false) { + if (! str_contains($line, '.')) { return $this->formatMessage($line, $args); } diff --git a/system/Log/Handlers/ChromeLoggerHandler.php b/system/Log/Handlers/ChromeLoggerHandler.php index b04d6f69238c..983ee274c6fc 100644 --- a/system/Log/Handlers/ChromeLoggerHandler.php +++ b/system/Log/Handlers/ChromeLoggerHandler.php @@ -142,7 +142,7 @@ protected function format($object) // @todo Modify formatting of objects once we can view them in browser. $objectArray = (array) $object; - $objectArray['___class_name'] = get_class($object); + $objectArray['___class_name'] = $object::class; return $objectArray; } diff --git a/system/Log/Handlers/FileHandler.php b/system/Log/Handlers/FileHandler.php index 88e384781a70..7c10d3231503 100644 --- a/system/Log/Handlers/FileHandler.php +++ b/system/Log/Handlers/FileHandler.php @@ -88,7 +88,7 @@ public function handle($level, $message): bool } // Instantiating DateTime with microseconds appended to initial date is needed for proper support of this format - if (strpos($this->dateFormat, 'u') !== false) { + if (str_contains($this->dateFormat, 'u')) { $microtimeFull = microtime(true); $microtimeShort = sprintf('%06d', ($microtimeFull - floor($microtimeFull)) * 1_000_000); $date = new DateTime(date('Y-m-d H:i:s.' . $microtimeShort, (int) $microtimeFull)); diff --git a/system/Log/Logger.php b/system/Log/Logger.php index 2c17ded5f7c9..f23b06cc3be9 100644 --- a/system/Log/Logger.php +++ b/system/Log/Logger.php @@ -339,7 +339,7 @@ protected function interpolate($message, array $context = []) $replace['{env}'] = ENVIRONMENT; // Allow us to log the file/line that we are logging from - if (strpos($message, '{file}') !== false) { + if (str_contains($message, '{file}')) { [$file, $line] = $this->determineFile(); $replace['{file}'] = $file; @@ -347,7 +347,7 @@ protected function interpolate($message, array $context = []) } // Match up environment variables in {env:foo} tags. - if (strpos($message, 'env:') !== false) { + if (str_contains($message, 'env:')) { preg_match('/env:[^}]+/', $message, $matches); foreach ($matches as $str) { diff --git a/system/Model.php b/system/Model.php index b64c8225e17c..84601fb0f074 100644 --- a/system/Model.php +++ b/system/Model.php @@ -504,7 +504,7 @@ protected function doErrors() return []; } - return [get_class($this->db) => $error['message']]; + return [$this->db::class => $error['message']]; } /** diff --git a/system/Pager/Pager.php b/system/Pager/Pager.php index b08cb00410fd..73d45d6a728d 100644 --- a/system/Pager/Pager.php +++ b/system/Pager/Pager.php @@ -425,7 +425,7 @@ protected function calculateCurrentPage(string $group) try { $this->groups[$group]['currentPage'] = (int) $this->groups[$group]['currentUri'] ->setSilent(false)->getSegment($this->segment[$group]); - } catch (HTTPException $e) { + } catch (HTTPException) { $this->groups[$group]['currentPage'] = 1; } } else { diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 589e88381ebe..75e84f45f8ed 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -70,9 +70,9 @@ class Publisher extends FileCollection * * @var array */ - private array $restrictions; + private readonly array $restrictions; - private ContentReplacer $replacer; + private readonly ContentReplacer $replacer; /** * Base path to use for the source. @@ -167,7 +167,7 @@ public function __construct(?string $source = null, ?string $destination = null) // Make sure the destination is allowed foreach (array_keys($this->restrictions) as $directory) { - if (strpos($this->destination, $directory) === 0) { + if (str_starts_with($this->destination, $directory)) { return; } } @@ -470,7 +470,7 @@ private function verifyAllowed(string $from, string $to): void { // Verify this is an allowed file for its destination foreach ($this->restrictions as $directory => $pattern) { - if (strpos($to, $directory) === 0 && self::matchFiles([$to], $pattern) === []) { + if (str_starts_with($to, $directory) && self::matchFiles([$to], $pattern) === []) { throw PublisherException::forFileNotAllowed($from, $directory, $pattern); } } diff --git a/system/RESTful/BaseResource.php b/system/RESTful/BaseResource.php index 1c21f65da860..269014ee8b77 100644 --- a/system/RESTful/BaseResource.php +++ b/system/RESTful/BaseResource.php @@ -69,7 +69,7 @@ public function setModel($which = null) } if (! empty($this->model) && empty($this->modelName)) { - $this->modelName = get_class($this->model); + $this->modelName = $this->model::class; } } } diff --git a/system/Router/AutoRouter.php b/system/Router/AutoRouter.php index 281b8a49732a..325eab77fdd8 100644 --- a/system/Router/AutoRouter.php +++ b/system/Router/AutoRouter.php @@ -13,66 +13,48 @@ use Closure; use CodeIgniter\Exceptions\PageNotFoundException; +use CodeIgniter\HTTP\ResponseInterface; /** * Router for Auto-Routing */ final class AutoRouter implements AutoRouterInterface { - /** - * List of CLI routes that do not contain '*' routes. - * - * @var array [routeKey => handler] - */ - private array $cliRoutes; - /** * Sub-directory that contains the requested controller class. * Primarily used by 'autoRoute'. */ private ?string $directory = null; - /** - * The name of the controller class. - */ - private string $controller; - - /** - * The name of the method to use. - */ - private string $method; - - /** - * Whether dashes in URI's should be converted - * to underscores when determining method names. - */ - private bool $translateURIDashes; - - /** - * HTTP verb for the request. - */ - private string $httpVerb; - - /** - * Default namespace for controllers. - */ - private string $defaultNamespace; - public function __construct( - array $cliRoutes, - string $defaultNamespace, - string $defaultController, - string $defaultMethod, - bool $translateURIDashes, - string $httpVerb + /** + * List of CLI routes that do not contain '*' routes. + * + * @var array [routeKey => handler] + */ + private readonly array $cliRoutes, + /** + * Default namespace for controllers. + */ + private readonly string $defaultNamespace, + /** + * The name of the controller class. + */ + private string $controller, + /** + * The name of the method to use. + */ + private string $method, + /** + * Whether dashes in URI's should be converted + * to underscores when determining method names. + */ + private bool $translateURIDashes, + /** + * HTTP verb for the request. + */ + private readonly string $httpVerb ) { - $this->cliRoutes = $cliRoutes; - $this->defaultNamespace = $defaultNamespace; - $this->translateURIDashes = $translateURIDashes; - $this->httpVerb = $httpVerb; - - $this->controller = $defaultController; - $this->method = $defaultMethod; } /** @@ -134,13 +116,13 @@ public function getRoute(string $uri, string $httpVerb): array $handler = strtolower($handler); // Like $routes->cli('hello/(:segment)', 'Home::$1') - if (strpos($handler, '::$') !== false) { + if (str_contains($handler, '::$')) { throw new PageNotFoundException( 'Cannot access CLI Route: ' . $uri ); } - if (strpos($handler, $controller . '::' . $methodName) === 0) { + if (str_starts_with($handler, $controller . '::' . $methodName)) { throw new PageNotFoundException( 'Cannot access CLI Route: ' . $uri ); @@ -166,7 +148,7 @@ public function getRoute(string $uri, string $httpVerb): array // Ensure the controller stores the fully-qualified class name // We have to check for a length over 1, since by default it will be '\' - if (strpos($this->controller, '\\') === false && strlen($this->defaultNamespace) > 1) { + if (! str_contains($this->controller, '\\') && strlen($this->defaultNamespace) > 1) { $this->controller = '\\' . ltrim( str_replace( '/', diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index a86e92f0161a..3c8da69e05f5 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -24,13 +24,6 @@ */ final class AutoRouterImproved implements AutoRouterInterface { - /** - * List of controllers in Defined Routes that should not be accessed via this Auto-Routing. - * - * @var class-string[] - */ - private array $protectedControllers; - /** * Sub-directory that contains the requested controller class. */ @@ -53,27 +46,11 @@ final class AutoRouterImproved implements AutoRouterInterface */ private array $params = []; - /** - * Whether dashes in URI's should be converted - * to underscores when determining method names. - */ - private bool $translateURIDashes; - /** * The namespace for controllers. */ private string $namespace; - /** - * The name of the default controller class. - */ - private string $defaultController; - - /** - * The name of the default method without HTTP verb prefix. - */ - private string $defaultMethod; - /** * The URI segments. * @@ -106,18 +83,24 @@ final class AutoRouterImproved implements AutoRouterInterface * @deprecated $httpVerb is deprecated. No longer used. */ public function __construct(// @phpstan-ignore-line - array $protectedControllers, + /** + * List of controllers in Defined Routes that should not be accessed via this Auto-Routing. + */ + private readonly array $protectedControllers, string $namespace, - string $defaultController, - string $defaultMethod, - bool $translateURIDashes, + private readonly string $defaultController, + /** + * The name of the default method without HTTP verb prefix. + */ + private readonly string $defaultMethod, + /** + * Whether dashes in URI's should be converted + * to underscores when determining method names. + */ + private readonly bool $translateURIDashes, string $httpVerb ) { - $this->protectedControllers = $protectedControllers; - $this->namespace = rtrim($namespace, '\\'); - $this->translateURIDashes = $translateURIDashes; - $this->defaultController = $defaultController; - $this->defaultMethod = $defaultMethod; + $this->namespace = rtrim($namespace, '\\'); // Set the default values $this->controller = $this->defaultController; @@ -344,7 +327,7 @@ public function getRoute(string $uri, string $httpVerb): array // Check parameter count try { $this->checkParameters($uri); - } catch (MethodNotFoundException $e) { + } catch (MethodNotFoundException) { throw PageNotFoundException::forControllerNotFound($this->controller, $this->method); } @@ -411,14 +394,14 @@ private function checkParameters(string $uri): void { try { $refClass = new ReflectionClass($this->controller); - } catch (ReflectionException $e) { + } catch (ReflectionException) { throw PageNotFoundException::forControllerNotFound($this->controller, $this->method); } try { $refMethod = $refClass->getMethod($this->method); $refParams = $refMethod->getParameters(); - } catch (ReflectionException $e) { + } catch (ReflectionException) { throw new MethodNotFoundException(); } @@ -445,7 +428,7 @@ private function checkRemap(): void 'AutoRouterImproved does not support `_remap()` method.' . ' Controller:' . $this->controller ); - } catch (ReflectionException $e) { + } catch (ReflectionException) { // Do nothing. } } @@ -459,7 +442,7 @@ private function checkUnderscore(string $uri): void $paramPos = $this->paramPos ?? count($this->segments); for ($i = 0; $i < $paramPos; $i++) { - if (strpos($this->segments[$i], '_') !== false) { + if (str_contains($this->segments[$i], '_')) { throw new PageNotFoundException( 'AutoRouterImproved prohibits access to the URI' . ' containing underscores ("' . $this->segments[$i] . '")' diff --git a/system/Router/DefinedRouteCollector.php b/system/Router/DefinedRouteCollector.php index 598efa6bb4d9..7fff8cfaac1f 100644 --- a/system/Router/DefinedRouteCollector.php +++ b/system/Router/DefinedRouteCollector.php @@ -21,11 +21,9 @@ */ final class DefinedRouteCollector { - private RouteCollection $routeCollection; - - public function __construct(RouteCollection $routes) - { - $this->routeCollection = $routes; + public function __construct( + private readonly RouteCollection $routeCollection + ) { } /** diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 47ac4b63b62e..5434322f2ccf 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -390,7 +390,7 @@ public function addPlaceholder($placeholder, ?string $pattern = null): RouteColl $placeholder = [$placeholder => $pattern]; } - $this->placeholders = array_merge($this->placeholders, $placeholder); + $this->placeholders = [...$this->placeholders, ...$placeholder]; return $this; } @@ -783,7 +783,7 @@ public function group(string $name, ...$params) if (isset($options['filter'])) { // Merge filters. $currentFilter = (array) ($this->currentOptions['filter'] ?? []); - $options['filter'] = array_merge($currentFilter, (array) $options['filter']); + $options['filter'] = [...$currentFilter, ...(array) $options['filter']]; } // Merge options other than filters. @@ -1147,7 +1147,7 @@ public function view(string $from, string $view, ?array $options = null): RouteC ->render($view, $options); $routeOptions = $options ?? []; - $routeOptions = array_merge($routeOptions, ['view' => $view]); + $routeOptions = [...$routeOptions, 'view' => $view]; $this->create(Method::GET, $from, $to, $routeOptions); @@ -1205,8 +1205,8 @@ public function reverseRoute(string $search, ...$params) // Add the default namespace if needed. $namespace = trim($this->defaultNamespace, '\\') . '\\'; if ( - substr($search, 0, 1) !== '\\' - && substr($search, 0, strlen($namespace)) !== $namespace + ! str_starts_with($search, '\\') + && ! str_starts_with($search, $namespace) ) { $search = $namespace . $search; } @@ -1230,7 +1230,7 @@ public function reverseRoute(string $search, ...$params) // If there's any chance of a match, then it will // be with $search at the beginning of the $to string. - if (strpos($to, $search) !== 0) { + if (! str_starts_with($to, $search)) { continue; } @@ -1352,7 +1352,7 @@ protected function buildReverseRoute(string $from, array $params): string preg_match_all('/\(([^)]+)\)/', $from, $matches); if (empty($matches[0])) { - if (strpos($from, '{locale}') !== false) { + if (str_contains($from, '{locale}')) { $locale = $params[0] ?? null; } @@ -1407,7 +1407,7 @@ protected function buildReverseRoute(string $from, array $params): string */ private function replaceLocale(string $route, ?string $locale = null): string { - if (strpos($route, '{locale}') === false) { + if (! str_contains($route, '{locale}')) { return $route; } @@ -1512,7 +1512,7 @@ protected function create(string $verb, string $from, $to, ?array $options = nul // If is redirect, No processing if (! isset($options['redirect']) && is_string($to)) { // If no namespace found, add the default namespace - if (strpos($to, '\\') === false || strpos($to, '\\') > 0) { + if (! str_contains($to, '\\') || strpos($to, '\\') > 0) { $namespace = $options['namespace'] ?? $this->defaultNamespace; $to = trim($namespace, '\\') . '\\' . $to; } @@ -1651,7 +1651,7 @@ private function determineCurrentSubdomain() // on the URL else parse_url will mis-interpret // 'host' as the 'path'. $url = $this->httpHost; - if (strpos($url, 'http') !== 0) { + if (! str_starts_with($url, 'http')) { $url = 'http://' . $url; } diff --git a/system/Router/Router.php b/system/Router/Router.php index e00031feb2d8..54005c812cd9 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -30,7 +30,7 @@ class Router implements RouterInterface /** * List of allowed HTTP methods (and CLI for command line use). */ - public const HTTP_METHODS = [ + final public const HTTP_METHODS = [ Method::GET, Method::HEAD, Method::POST, @@ -406,7 +406,7 @@ protected function checkRoutes(string $uri): bool $matchedKey = $routeKey; // Are we dealing with a locale? - if (strpos($routeKey, '{locale}') !== false) { + if (str_contains($routeKey, '{locale}')) { $routeKey = str_replace('{locale}', '[^/]+', $routeKey); } @@ -428,7 +428,7 @@ protected function checkRoutes(string $uri): bool } // Store our locale so CodeIgniter object can // assign it to the Request. - if (strpos($matchedKey, '{locale}') !== false) { + if (str_contains($matchedKey, '{locale}')) { preg_match( '#^' . str_replace('{locale}', '(?[^/]+)', $matchedKey) . '$#u', $uri, @@ -465,13 +465,13 @@ protected function checkRoutes(string $uri): bool [$controller] = explode('::', $handler); // Checks `/` in controller name - if (strpos($controller, '/') !== false) { + if (str_contains($controller, '/')) { throw RouterException::forInvalidControllerName($handler); } - if (strpos($handler, '$') !== false && strpos($routeKey, '(') !== false) { + if (str_contains($handler, '$') && str_contains($routeKey, '(')) { // Checks dynamic controller - if (strpos($controller, '$') !== false) { + if (str_contains($controller, '$')) { throw RouterException::forDynamicController($handler); } diff --git a/system/Security/Security.php b/system/Security/Security.php index 9c28b82335b0..9a226a576efd 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -159,7 +159,7 @@ class Security implements SecurityInterface */ protected $samesite = Cookie::SAMESITE_LAX; - private IncomingRequest $request; + private readonly IncomingRequest $request; /** * CSRF Cookie Name without Prefix @@ -292,7 +292,7 @@ public function verify(RequestInterface $request) try { $token = ($postedToken !== null && $this->config->tokenRandomize) ? $this->derandomize($postedToken) : $postedToken; - } catch (InvalidArgumentException $e) { + } catch (InvalidArgumentException) { $token = null; } diff --git a/system/Session/Session.php b/system/Session/Session.php index 4e4a01581ba2..45f6e4090f32 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -505,7 +505,7 @@ public function get(?string $key = null) } $userdata = []; - $_exclude = array_merge(['__ci_vars'], $this->getFlashKeys(), $this->getTempKeys()); + $_exclude = ['__ci_vars', ...$this->getFlashKeys(), ...$this->getTempKeys()]; $keys = array_keys($_SESSION); @@ -537,7 +537,7 @@ public function has(string $key): bool public function push(string $key, array $data) { if ($this->has($key) && is_array($value = $this->get($key))) { - $this->set($key, array_merge($value, $data)); + $this->set($key, [...$value, ...$data]); } } diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index 266a22b0161d..40a4da68153e 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -477,7 +477,7 @@ public function assertCloseEnoughString($expected, $actual, string $message = '' $difference = abs($expected - $actual); $this->assertLessThanOrEqual($tolerance, $difference, $message); - } catch (Exception $e) { + } catch (Exception) { return false; } } @@ -515,7 +515,7 @@ protected function getHeaderEmitted(string $header, bool $ignoreCase = false, st foreach (xdebug_get_headers() as $emittedHeader) { $found = $ignoreCase ? (stripos($emittedHeader, $header) === 0) - : (strpos($emittedHeader, $header) === 0); + : (str_starts_with($emittedHeader, $header)); if ($found) { return $emittedHeader; diff --git a/system/Test/ControllerTestTrait.php b/system/Test/ControllerTestTrait.php index a99b899eaf63..25a8416d17d6 100644 --- a/system/Test/ControllerTestTrait.php +++ b/system/Test/ControllerTestTrait.php @@ -202,7 +202,7 @@ public function execute(string $method, ...$params) // getStatusCode() throws for empty codes try { $response->getStatusCode(); - } catch (HTTPException $e) { + } catch (HTTPException) { // If no code has been set then assume success $response->setStatusCode(200); } diff --git a/system/Test/DOMParser.php b/system/Test/DOMParser.php index 1a2cbb0d61aa..4cc56071670a 100644 --- a/system/Test/DOMParser.php +++ b/system/Test/DOMParser.php @@ -258,11 +258,11 @@ public function parseSelector(string $selector) $attr = null; // ID? - if (strpos($selector, '#') !== false) { + if (str_contains($selector, '#')) { [$tag, $id] = explode('#', $selector); } // Attribute - elseif (strpos($selector, '[') !== false && strpos($selector, ']') !== false) { + elseif (str_contains($selector, '[') && str_contains($selector, ']')) { $open = strpos($selector, '['); $close = strpos($selector, ']'); @@ -280,7 +280,7 @@ public function parseSelector(string $selector) $attr = [$name => trim($value, '] ')]; } // Class? - elseif (strpos($selector, '.') !== false) { + elseif (str_contains($selector, '.')) { [$tag, $class] = explode('.', $selector); } // Otherwise, assume the entire string is our tag diff --git a/system/Test/DatabaseTestTrait.php b/system/Test/DatabaseTestTrait.php index d7b8b02ddaa8..247cc74ee564 100644 --- a/system/Test/DatabaseTestTrait.php +++ b/system/Test/DatabaseTestTrait.php @@ -239,7 +239,7 @@ protected function clearInsertCache() */ public function loadBuilder(string $tableName) { - $builderClass = str_replace('Connection', 'Builder', get_class($this->db)); + $builderClass = str_replace('Connection', 'Builder', $this->db::class); return new $builderClass($tableName, $this->db); } diff --git a/system/Test/Fabricator.php b/system/Test/Fabricator.php index 3a28f281d127..66a685fc8d30 100644 --- a/system/Test/Fabricator.php +++ b/system/Test/Fabricator.php @@ -305,7 +305,7 @@ protected function guessFormatter($field): string $this->faker->getFormatter($field); return $field; - } catch (InvalidArgumentException $e) { + } catch (InvalidArgumentException) { // No match, keep going } @@ -497,18 +497,11 @@ public function create(?int $count = null, bool $mock = false) */ protected function createMock(?int $count = null) { - switch ($this->model->dateFormat) { - case 'datetime': - $datetime = date('Y-m-d H:i:s'); - break; - - case 'date': - $datetime = date('Y-m-d'); - break; - - default: - $datetime = Time::now()->getTimestamp(); - } + $datetime = match ($this->model->dateFormat) { + 'datetime' => date('Y-m-d H:i:s'), + 'date' => date('Y-m-d'), + default => Time::now()->getTimestamp(), + }; // Determine which fields we will need $fields = []; diff --git a/system/Test/FilterTestTrait.php b/system/Test/FilterTestTrait.php index 523717e54679..14bf81db9271 100644 --- a/system/Test/FilterTestTrait.php +++ b/system/Test/FilterTestTrait.php @@ -131,7 +131,7 @@ protected function getFilterCaller($filter, string $position): Closure if (is_string($filter)) { // Check for an alias (no namespace) - if (strpos($filter, '\\') === false) { + if (! str_contains($filter, '\\')) { if (! isset($this->filtersConfig->aliases[$filter])) { throw new RuntimeException("No filter found with alias '{$filter}'"); } @@ -149,7 +149,7 @@ protected function getFilterCaller($filter, string $position): Closure $filter = new $class(); if (! $filter instanceof FilterInterface) { - throw FilterException::forIncorrectInterface(get_class($filter)); + throw FilterException::forIncorrectInterface($filter::class); } $filterInstances[] = $filter; diff --git a/system/Test/TestLogger.php b/system/Test/TestLogger.php index dce1277d98d2..3f453ca5cb0d 100644 --- a/system/Test/TestLogger.php +++ b/system/Test/TestLogger.php @@ -80,7 +80,7 @@ public static function didLog(string $level, $message, bool $useExactComparison continue; } - if (strpos($log['message'], $message) !== false) { + if (str_contains($log['message'], $message)) { return true; } } diff --git a/system/Typography/Typography.php b/system/Typography/Typography.php index fd763cd52e86..301f03227f53 100644 --- a/system/Typography/Typography.php +++ b/system/Typography/Typography.php @@ -82,7 +82,7 @@ public function autoTypography(string $str, bool $reduceLinebreaks = false): str } // Standardize Newlines to make matching easier - if (strpos($str, "\r") !== false) { + if (str_contains($str, "\r")) { $str = str_replace(["\r\n", "\r"], "\n", $str); } @@ -94,7 +94,7 @@ public function autoTypography(string $str, bool $reduceLinebreaks = false): str // HTML comment tags don't conform to patterns of normal tags, so pull them out separately, only if needed $htmlComments = []; - if (strpos($str, '