• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codeigniter4 / CodeIgniter4 / 21507027100

30 Jan 2026 06:43AM UTC coverage: 85.382% (-0.1%) from 85.527%
21507027100

Pull #9889

github

web-flow
Merge b4eed135b into fc0cb1924
Pull Request #9889: feat: FrankenPHP Worker Mode

153 of 243 new or added lines in 19 files covered. (62.96%)

1 existing line in 1 file now uncovered.

22119 of 25906 relevant lines covered (85.38%)

205.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/system/Boot.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter;
15

16
use CodeIgniter\Cache\FactoriesCache;
17
use CodeIgniter\CLI\Console;
18
use CodeIgniter\Config\DotEnv;
19
use Config\App;
20
use Config\Autoload;
21
use Config\Modules;
22
use Config\Optimize;
23
use Config\Paths;
24
use Config\Services;
25

26
/**
27
 * Bootstrap for the application
28
 *
29
 * @codeCoverageIgnore
30
 */
31
class Boot
32
{
33
    /**
34
     * Used by `public/index.php`
35
     *
36
     * Context
37
     *   web:     Invoked by HTTP request
38
     *   php-cli: Invoked by CLI via `php public/index.php`
39
     *
40
     * @return int Exit code.
41
     */
42
    public static function bootWeb(Paths $paths): int
43
    {
44
        static::definePathConstants($paths);
×
45
        if (! defined('APP_NAMESPACE')) {
×
46
            static::loadConstants();
×
47
        }
48
        static::checkMissingExtensions();
×
49

50
        static::loadDotEnv($paths);
×
51
        static::defineEnvironment();
×
52
        static::loadEnvironmentBootstrap($paths);
×
53

54
        static::loadCommonFunctions();
×
55
        static::loadAutoloader();
×
56
        static::setExceptionHandler();
×
57
        static::initializeKint();
×
58

59
        $configCacheEnabled = class_exists(Optimize::class)
×
60
            && (new Optimize())->configCacheEnabled;
×
61
        if ($configCacheEnabled) {
×
62
            $factoriesCache = static::loadConfigCache();
×
63
        }
64

65
        static::autoloadHelpers();
×
66

67
        $app = static::initializeCodeIgniter();
×
68
        static::runCodeIgniter($app);
×
69

70
        if ($configCacheEnabled) {
×
71
            static::saveConfigCache($factoriesCache);
×
72
        }
73

74
        // Exits the application, setting the exit code for CLI-based
75
        // applications that might be watching.
76
        return EXIT_SUCCESS;
×
77
    }
78

79
    /**
80
     * Bootstrap for FrankenPHP worker mode.
81
     *
82
     * This method performs one-time initialization for worker mode,
83
     * loading everything except the CodeIgniter instance, which should
84
     * be created fresh for each request.
85
     *
86
     * @used-by `public/frankenphp-worker.php`
87
     */
88
    public static function bootWorker(Paths $paths): CodeIgniter
89
    {
NEW
90
        static::definePathConstants($paths);
×
NEW
91
        if (! defined('APP_NAMESPACE')) {
×
NEW
92
            static::loadConstants();
×
93
        }
NEW
94
        static::checkMissingExtensions();
×
95

NEW
96
        static::loadDotEnv($paths);
×
NEW
97
        static::defineEnvironment();
×
NEW
98
        static::loadEnvironmentBootstrap($paths);
×
99

NEW
100
        static::loadCommonFunctions();
×
NEW
101
        static::loadAutoloader();
×
NEW
102
        static::setExceptionHandler();
×
NEW
103
        static::initializeKint();
×
104

NEW
105
        static::checkOptimizationsForWorker();
×
106

NEW
107
        static::autoloadHelpers();
×
108

NEW
109
        return Boot::initializeCodeIgniter();
×
110
    }
111

112
    /**
113
     * Used by command line scripts other than
114
     * * `spark`
115
     * * `php-cli`
116
     * * `phpunit`
117
     *
118
     * @used-by `system/util_bootstrap.php`
119
     */
120
    public static function bootConsole(Paths $paths): void
121
    {
122
        static::definePathConstants($paths);
×
123
        static::loadConstants();
×
124
        static::checkMissingExtensions();
×
125

126
        static::loadDotEnv($paths);
×
127
        static::loadEnvironmentBootstrap($paths);
×
128

129
        static::loadCommonFunctions();
×
130
        static::loadAutoloader();
×
131
        static::setExceptionHandler();
×
132
        static::initializeKint();
×
133
        static::autoloadHelpers();
×
134

135
        // We need to force the request to be a CLIRequest since we're in console
136
        Services::createRequest(new App(), true);
×
137
        service('routes')->loadRoutes();
×
138
    }
139

140
    /**
141
     * Used by `spark`
142
     *
143
     * @return int Exit code.
144
     */
145
    public static function bootSpark(Paths $paths): int
146
    {
147
        static::definePathConstants($paths);
×
148
        if (! defined('APP_NAMESPACE')) {
×
149
            static::loadConstants();
×
150
        }
151
        static::checkMissingExtensions();
×
152

153
        static::loadDotEnv($paths);
×
154
        static::defineEnvironment();
×
155
        static::loadEnvironmentBootstrap($paths);
×
156

157
        static::loadCommonFunctions();
×
158
        static::loadAutoloader();
×
159
        static::setExceptionHandler();
×
160
        static::initializeKint();
×
161
        static::autoloadHelpers();
×
162

163
        static::initializeCodeIgniter();
×
164
        $console = static::initializeConsole();
×
165

166
        return static::runCommand($console);
×
167
    }
168

169
    /**
170
     * Used by `system/Test/bootstrap.php`
171
     */
172
    public static function bootTest(Paths $paths): void
173
    {
174
        static::loadConstants();
×
175
        static::checkMissingExtensions();
×
176

177
        static::loadDotEnv($paths);
×
178
        static::loadEnvironmentBootstrap($paths, false);
×
179

180
        static::loadCommonFunctionsMock();
×
181
        static::loadCommonFunctions();
×
182

183
        static::loadAutoloader();
×
184
        static::setExceptionHandler();
×
185
        static::initializeKint();
×
186
        static::autoloadHelpers();
×
187
    }
188

189
    /**
190
     * Used by `preload.php`
191
     */
192
    public static function preload(Paths $paths): void
193
    {
194
        static::definePathConstants($paths);
×
195
        static::loadConstants();
×
196
        static::defineEnvironment();
×
197
        static::loadEnvironmentBootstrap($paths, false);
×
198

199
        static::loadAutoloader();
×
200
    }
201

202
    /**
203
     * Load environment settings from .env files into $_SERVER and $_ENV
204
     */
205
    protected static function loadDotEnv(Paths $paths): void
206
    {
207
        require_once $paths->systemDirectory . '/Config/DotEnv.php';
×
208
        $envDirectory = $paths->envDirectory ?? $paths->appDirectory . '/../';
×
209
        (new DotEnv($envDirectory))->load();
×
210
    }
211

212
    protected static function defineEnvironment(): void
213
    {
214
        if (! defined('ENVIRONMENT')) {
×
215
            // @phpstan-ignore-next-line
216
            $env = $_ENV['CI_ENVIRONMENT'] ?? $_SERVER['CI_ENVIRONMENT']
×
217
                ?? getenv('CI_ENVIRONMENT')
×
218
                ?: 'production';
×
219

220
            define('ENVIRONMENT', $env);
×
221
        }
222
    }
223

224
    protected static function loadEnvironmentBootstrap(Paths $paths, bool $exit = true): void
225
    {
226
        if (is_file($paths->appDirectory . '/Config/Boot/' . ENVIRONMENT . '.php')) {
×
227
            require_once $paths->appDirectory . '/Config/Boot/' . ENVIRONMENT . '.php';
×
228

229
            return;
×
230
        }
231

232
        if ($exit) {
×
233
            header('HTTP/1.1 503 Service Unavailable.', true, 503);
×
234
            echo 'The application environment is not set correctly.';
×
235

236
            exit(EXIT_ERROR);
×
237
        }
238
    }
239

240
    /**
241
     * The path constants provide convenient access to the folders throughout
242
     * the application. We have to set them up here, so they are available in
243
     * the config files that are loaded.
244
     */
245
    protected static function definePathConstants(Paths $paths): void
246
    {
247
        // The path to the application directory.
248
        if (! defined('APPPATH')) {
×
249
            define('APPPATH', realpath(rtrim($paths->appDirectory, '\\/ ')) . DIRECTORY_SEPARATOR);
×
250
        }
251

252
        // The path to the project root directory. Just above APPPATH.
253
        if (! defined('ROOTPATH')) {
×
254
            define('ROOTPATH', realpath(APPPATH . '../') . DIRECTORY_SEPARATOR);
×
255
        }
256

257
        // The path to the system directory.
258
        if (! defined('SYSTEMPATH')) {
×
259
            define('SYSTEMPATH', realpath(rtrim($paths->systemDirectory, '\\/ ')) . DIRECTORY_SEPARATOR);
×
260
        }
261

262
        // The path to the writable directory.
263
        if (! defined('WRITEPATH')) {
×
264
            $writePath = realpath(rtrim($paths->writableDirectory, '\\/ '));
×
265

266
            if ($writePath === false) {
×
267
                header('HTTP/1.1 503 Service Unavailable.', true, 503);
×
268
                echo 'The WRITEPATH is not set correctly.';
×
269

270
                // EXIT_ERROR is not yet defined
271
                exit(1);
×
272
            }
273
            define('WRITEPATH', $writePath . DIRECTORY_SEPARATOR);
×
274
        }
275

276
        // The path to the tests directory
277
        if (! defined('TESTPATH')) {
×
278
            define('TESTPATH', realpath(rtrim($paths->testsDirectory, '\\/ ')) . DIRECTORY_SEPARATOR);
×
279
        }
280
    }
281

282
    protected static function loadConstants(): void
283
    {
284
        require_once APPPATH . 'Config/Constants.php';
×
285
    }
286

287
    protected static function loadCommonFunctions(): void
288
    {
289
        // Require app/Common.php file if exists.
290
        if (is_file(APPPATH . 'Common.php')) {
×
291
            require_once APPPATH . 'Common.php';
×
292
        }
293

294
        // Require system/Common.php
295
        require_once SYSTEMPATH . 'Common.php';
×
296
    }
297

298
    protected static function loadCommonFunctionsMock(): void
299
    {
300
        require_once SYSTEMPATH . 'Test/Mock/MockCommon.php';
×
301
    }
302

303
    /**
304
     * The autoloader allows all the pieces to work together in the framework.
305
     * We have to load it here, though, so that the config files can use the
306
     * path constants.
307
     */
308
    protected static function loadAutoloader(): void
309
    {
310
        if (! class_exists(Autoload::class, false)) {
×
311
            require_once SYSTEMPATH . 'Config/AutoloadConfig.php';
×
312
            require_once APPPATH . 'Config/Autoload.php';
×
313
            require_once SYSTEMPATH . 'Modules/Modules.php';
×
314
            require_once APPPATH . 'Config/Modules.php';
×
315
        }
316

317
        require_once SYSTEMPATH . 'Autoloader/Autoloader.php';
×
318
        require_once SYSTEMPATH . 'Config/BaseService.php';
×
319
        require_once SYSTEMPATH . 'Config/Services.php';
×
320
        require_once APPPATH . 'Config/Services.php';
×
321

322
        // Initialize and register the loader with the SPL autoloader stack.
323
        Services::autoloader()->initialize(new Autoload(), new Modules())->register();
×
324
    }
325

326
    protected static function autoloadHelpers(): void
327
    {
328
        service('autoloader')->loadHelpers();
×
329
    }
330

331
    protected static function setExceptionHandler(): void
332
    {
333
        service('exceptions')->initialize();
×
334
    }
335

336
    protected static function checkMissingExtensions(): void
337
    {
338
        if (is_file(COMPOSER_PATH)) {
×
339
            return;
×
340
        }
341

342
        // Run this check for manual installations
343
        $missingExtensions = [];
×
344

345
        foreach ([
×
346
            'intl',
×
347
            'mbstring',
×
348
        ] as $extension) {
×
349
            if (! extension_loaded($extension)) {
×
350
                $missingExtensions[] = $extension;
×
351
            }
352
        }
353

354
        if ($missingExtensions === []) {
×
355
            return;
×
356
        }
357

358
        $message = sprintf(
×
359
            'The framework needs the following extension(s) installed and loaded: %s.',
×
360
            implode(', ', $missingExtensions),
×
361
        );
×
362

363
        header('HTTP/1.1 503 Service Unavailable.', true, 503);
×
364
        echo $message;
×
365

366
        exit(EXIT_ERROR);
×
367
    }
368

369
    protected static function checkOptimizationsForWorker(): void
370
    {
NEW
371
        if (class_exists(Optimize::class)) {
×
NEW
372
            $optimize = new Optimize();
×
373

NEW
374
            if ($optimize->configCacheEnabled || $optimize->locatorCacheEnabled) {
×
NEW
375
                echo 'Optimization settings (configCacheEnabled, locatorCacheEnabled) '
×
NEW
376
                    . 'must be disabled in Config\Optimize when running in Worker Mode.';
×
377

NEW
378
                exit(EXIT_ERROR);
×
379
            }
380
        }
381
    }
382

383
    protected static function initializeKint(): void
384
    {
385
        service('autoloader')->initializeKint(CI_DEBUG);
×
386
    }
387

388
    protected static function loadConfigCache(): FactoriesCache
389
    {
390
        $factoriesCache = new FactoriesCache();
×
391
        $factoriesCache->load('config');
×
392

393
        return $factoriesCache;
×
394
    }
395

396
    /**
397
     * The CodeIgniter class contains the core functionality to make
398
     * the application run, and does all the dirty work to get
399
     * the pieces all working together.
400
     */
401
    protected static function initializeCodeIgniter(): CodeIgniter
402
    {
403
        $app = service('codeigniter');
×
404
        $app->initialize();
×
405
        $context = is_cli() ? 'php-cli' : 'web';
×
406
        $app->setContext($context);
×
407

408
        return $app;
×
409
    }
410

411
    /**
412
     * Now that everything is set up, it's time to actually fire
413
     * up the engines and make this app do its thang.
414
     */
415
    protected static function runCodeIgniter(CodeIgniter $app): void
416
    {
417
        $app->run();
×
418
    }
419

420
    protected static function saveConfigCache(FactoriesCache $factoriesCache): void
421
    {
422
        $factoriesCache->save('config');
×
423
    }
424

425
    protected static function initializeConsole(): Console
426
    {
427
        $console = new Console();
×
428

429
        // Show basic information before we do anything else.
430
        if (is_int($suppress = array_search('--no-header', $_SERVER['argv'], true))) {
×
431
            unset($_SERVER['argv'][$suppress]);
×
432
            $suppress = true;
×
433
        }
434

435
        $console->showHeader($suppress);
×
436

437
        return $console;
×
438
    }
439

440
    protected static function runCommand(Console $console): int
441
    {
442
        $exit = $console->run();
×
443

444
        return is_int($exit) ? $exit : EXIT_SUCCESS;
×
445
    }
446
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc