A few years ago, I debugged a production outage that came down to one line: an optional UI partial was loaded with require instead of include. The file wasn’t present on one node after a deploy artifact hiccup, and the entire request pipeline hard-stopped. The fix was one character long, but the lesson stuck: in PHP, file inclusion isn’t “just” a convenience feature—it’s control flow.
When you pull another PHP file into the current script, you’re not importing a module the way you might in JavaScript or Python. You’re literally asking the engine to read another file and execute it in-place, as if you pasted it right there. That means errors, scope, and return values behave in ways that affect reliability.
In this post I’ll show you exactly how require and include differ, how those differences appear in real applications, and the patterns I recommend today: require for bootstrapping and invariants, include for optional fragments, and “don’t include at all” when a modern autoloadable design is the better move. Along the way I’ll cover *_once, path resolution pitfalls, security gotchas, and the performance realities you actually feel in production.
What These Constructs Really Do (It’s Not “Import”)
If you come from ecosystems with explicit module systems, it’s easy to assume include() and require() behave like dependency declarations. In PHP they are better described as “evaluate another file here.” They are language constructs (often called “functions” in everyday conversation) that:
- Read the target file
- Parse it as PHP (and pass through any literal HTML output)
- Execute it in the current context
That “current context” piece is important. Included files can:
- Access variables from the calling scope
- Define functions/classes that become available afterward
- Emit output immediately (which can break headers/cookies if you’re not careful)
- Return a value back to the caller
A simple analogy I use when teaching teams: include/require are closer to pasting code into a document than linking to another document. That’s why the “what happens when the file isn’t there?” question is so consequential.
Parentheses, return values, and why “function” wording confuses people
You’ll see both require ‘file.php‘; and require(‘file.php‘);. Both are valid. I usually write without parentheses for readability.
Both constructs also yield a value:
- If the included file executes a
return, that return value becomes the value ofinclude/require. - If the included file does not return anything, the expression evaluates to
1on success. - If
includefails, it evaluates tofalse(and emits a warning). This detail matters when you intentionally treat inclusion as optional.
That behavior becomes surprisingly useful for configuration patterns and feature flags later.
The Real Difference: Failure Semantics and Error Levels
Here’s the part that matters operationally.
includeemits a warning when it cannot load the file and then keeps running.requireemits a warning and then triggers a fatal error that stops script execution.
When the file is missing or not readable, you generally see:
include:E_WARNING(“failed to open stream…”) and execution continues.require: warning plus a fatal error, and execution stops.
That difference turns require into an assertion: “this file must exist for the program to make sense.”
Minimal runnable demo: missing file behavior
Create index.php:
<?php
declare(strict_types=1);
echo ‘Step 1: before include‘ . PHP_EOL;
include DIR . ‘/optional-fragment.php‘;
echo ‘Step 2: after include (you will see this even if the file is missing)‘ . PHP_EOL;
echo ‘Step 3: before require‘ . PHP_EOL;
require DIR . ‘/mandatory-bootstrap.php‘;
echo ‘Step 4: after require (you will NOT see this if the file is missing)‘ . PHP_EOL;
Run it with:
php index.php
If both files are missing, you’ll still see “Step 2”, but you won’t see “Step 4”. That’s the difference you plan around.
My rule in production
- If the request cannot be handled correctly without the file, I use
require. - If the file improves the experience but the request can still be handled safely without it, I use
include.
Notice the word “safely.” Continuing execution after a missing file can be worse than failing fast if your program assumes functions/constants from that file exist.
Choosing the Right Tool: Mandatory Bootstrapping vs Optional Fragments
Most codebases include files for a few recurring reasons:
1) Bootstrapping: configuration, container setup, autoloaders, environment wiring
2) Shared layout fragments: header/footer, navigation, optional widgets
3) Feature toggles: conditional bits that load only when enabled
4) Legacy architecture: “include a bunch of function files”
Here’s how I map that to constructs.
When I use require
I reach for require when the file is part of the program’s invariants:
- Autoloader registration (for projects using Composer’s autoloader)
- Core configuration that defines database credentials, secrets, environment mode
- A bootstrap that sets up error handling and routing
- Contracts your code relies on immediately (constants, critical functions)
Example: application bootstrap
<?php
declare(strict_types=1);
// If this fails, the app cannot sensibly continue.
require DIR . ‘/vendor/autoload.php‘;
require DIR . ‘/bootstrap/app.php‘;
$app = App\Kernel::boot();
$response = $app->handle();
$response->send();
If vendor/autoload.php is missing, you want a hard failure because the runtime is in an invalid state.
When I use include
I use include for optional presentation fragments or non-critical add-ons:
- Optional template partials
- “Nice to have” widgets (marketing banner, seasonal notice)
- Diagnostics panels in non-production modes (still with caution)
Example: optional template fragment
<?php
declare(strict_types=1);
$title = $title ?? ‘Account‘;
?>
<?php include DIR . ‘/partials/navbar.php‘; ?>
Welcome back.
<?php include DIR . ‘/partials/analytics-snippet.php‘; ?>
If analytics-snippet.php is missing, you probably want the page to render anyway. But if navbar.php contains logic your page assumes (like setting a CSRF token), I’d switch that to require.
A practical decision table
My choice
—
require
require
include
include (with guard)
require
Scope, Output, and “Paste-in-Place” Side Effects
The second-order effects of includes cause most real bugs I see.
Variable scope is shared (sometimes unexpectedly)
Included files execute in the scope where they’re included. That means variables are visible both ways.
Create user-card.php:
<?php
declare(strict_types=1);
// Expects $user to exist.
echo ‘‘;
echo ‘
‘ . htmlspecialchars($user[‘name‘], ENT_QUOTES, ‘UTF-8‘) . ‘
‘;
echo ‘
‘ . htmlspecialchars($user[‘email‘], ENT_QUOTES, ‘UTF-8‘) . ‘
‘;
echo ‘‘;
And profile.php:
<?php
declare(strict_types=1);
$user = [
‘name‘ => ‘Amina Rahman‘,
‘email‘ => ‘[email protected]‘,
];
include DIR . ‘/user-card.php‘;
This works, but it’s also brittle: user-card.php silently depends on $user. In modern codebases, I prefer passing data explicitly via functions/components (or a template engine), but when you’re in raw PHP templates, I at least standardize on a clear $viewModel array and document required keys.
A pattern I like in plain PHP templates is to pass a single array with an obvious name:
<?php
declare(strict_types=1);
$view = [
‘user‘ => $user,
‘title‘ => ‘Profile‘,
];
include DIR . ‘/templates/profile.php‘;
Then, inside the template, I only read $view[...]. It’s not perfect, but it reduces “mystery variables” and makes templates easier to search and refactor.
Included files can emit output immediately
If an included file prints output before you send headers/cookies, you can hit classic “headers already sent” issues.
In my experience, this bites teams when:
- A debug include echoes something
- A file has stray whitespace before
<?php - A partial contains HTML earlier than expected
For any include that might run before headers are set, I keep it “PHP-only” (no raw HTML) and have it return data instead of printing.
If I need to include something that generates markup but I can’t risk it printing early, I use output buffering intentionally:
<?php
declare(strict_types=1);
ob_start();
include DIR . ‘/partials/banner.php‘;
$bannerHtml = obgetclean();
// Now I control when it is emitted.
header(‘X-Banner-Loaded: 1‘);
echo $bannerHtml;
Output buffering is not a license to be sloppy, but it’s a practical tool for isolating legacy templates.
include/require return values are real tools
You can structure config like this:
config/database.php
<?php
declare(strict_types=1);
return [
‘dsn‘ => ‘mysql:host=127.0.0.1;dbname=app‘,
‘user‘ => ‘app‘,
‘password‘ => getenv(‘DB_PASSWORD‘) ?: ‘‘,
];
bootstrap.php
<?php
declare(strict_types=1);
$db = require DIR . ‘/config/database.php‘;
$pdo = new PDO($db[‘dsn‘], $db[‘user‘], $db[‘password‘]);
That “require returns the array” pattern is clean, testable, and avoids global variables.
One subtlety: if a config file accidentally echoes something, it can corrupt JSON responses or break redirects. In config files that return arrays, I keep them strictly PHP (no closing ?> tag, no HTML) to reduce the chance of accidental output.
Error Handling Nuances: Warnings, Fatals, and Making Failure Explicit
The include/require headline difference is “warning vs fatal,” but real applications run with custom error handlers, logging, and frameworks that can shift what you observe.
include failure is a warning, but it also returns false
This is the simplest way to treat include as optional without relying on warnings:
<?php
declare(strict_types=1);
$result = @include DIR . ‘/partials/optional.php‘;
if ($result === false) {
// Optional file missing or unreadable.
error_log(‘Optional include failed‘);
}
I’m intentionally showing @ here because people use it, but I don’t recommend it as a default. Suppressing warnings can hide useful signals in staging and make debugging harder. In most apps, I’d rather avoid suppression and instead guard with isfile() or isreadable().
A better “no warning noise” pattern is:
<?php
declare(strict_types=1);
$path = DIR . ‘/partials/optional.php‘;
if (isfile($path) && isreadable($path)) {
include $path;
}
This avoids emitting warnings in the first place, while making the optionality explicit.
require is not catchable in the usual way
A missing require triggers a fatal error that stops script execution. That’s the point: it’s a hard assertion.
Developers sometimes ask, “Can I catch it with try/catch?” In typical PHP usage, the failure mode of a missing require is not a regular exception you can catch and continue. If you want recoverable behavior, that’s a strong signal that include (plus an explicit guard) is the correct tool.
Custom error handlers can turn warnings into exceptions
Some codebases convert warnings into ErrorException via seterrorhandler(). In that world, include can behave like “throw an exception” (and stop execution unless caught), which can surprise you if you’re expecting it to keep running.
If your project does this, I recommend you treat inclusion as a boundary with clear intent:
- For mandatory files:
requireand let it fail loudly. - For optional files: guard with
is_file()and log intentionally.
That gives you stable behavior regardless of how warnings are handled.
A practical “optional include with observable behavior” helper
When I have many optional fragments (especially in legacy view layers), I sometimes centralize the pattern:
<?php
declare(strict_types=1);
function include_optional(string $path, array $context = []): bool
{
if (!isfile($path) || !isreadable($path)) {
error_log(‘Optional include missing: ‘ . $path);
return false;
}
// Make context variables available to the included file.
extract($context, EXTR_SKIP);
include $path;
return true;
}
Used like this:
<?php
include_optional(DIR . ‘/partials/promo.php‘, [
‘user‘ => $user,
‘plan‘ => $plan,
]);
I’m careful with extract() (more on that later), but as a migration tool it can reduce duplicated boilerplate while still being explicit about optionality.
includeonce and requireonce: Convenience with a Cost
includeonce and requireonce ensure a file is included only one time per request. They’re helpful when:
- You include a file from multiple entry points
- You have legacy code that defines functions/constants and would redeclare otherwise
What changes with *_once
- On each call, PHP must decide whether the target file has already been included.
- That means extra work: path resolution plus bookkeeping.
In modern projects, I typically avoid *once for application code and rely on autoloading + namespaces for classes, and explicit “bootstrap runs once” entry points. That said, in legacy systems where you can’t quickly untangle includes, requireonce can be the safer choice.
Example: preventing redeclaration
helpers.php
<?php
declare(strict_types=1);
function format_money(int $cents): string
{
return ‘$‘ . number_format($cents / 100, 2);
}
page-a.php and page-b.php both need it:
<?php
declare(strict_types=1);
require_once DIR . ‘/helpers.php‘;
echo format_money(12345);
Without _once, a double-include can cause a fatal “cannot redeclare function” error.
How “once” decides what counts as the same file
The tricky part is that “the same file” is determined by the resolved path PHP records for included files. If you include the same physical file through two different paths (for example, via symlinks, relative segments like ../, or different working directories), you can get surprising behavior.
My practical rule is simple: always use normalized, absolute-ish paths built from DIR (and avoid clever includepath tricks). That dramatically reduces weirdness around once.
My 2026 recommendation
- Prefer Composer autoloading for classes.
- Prefer files that
returnvalues for config. - Use
require_oncesparingly for legacy helper files you can’t refactor immediately.
Path Resolution: The Bugs You Don’t See Until Deploy Day
A huge portion of “works locally, fails in production” include issues are path issues.
Relative paths are relative to the current working directory (not always the file)
If you do:
include ‘partials/footer.php‘;
…PHP resolves that relative to the runtime’s current working directory, which can vary depending on the entry point, server configuration, CLI invocation, or test runner.
This is one of those bugs that hides until you:
- Add a second front controller (a CLI script, a queue worker, a cron job)
- Run the same code under a different document root
- Change how the process is launched (systemd, supervisor, container entrypoint)
Use DIR (or dirname(FILE)) for stable paths
I recommend:
include DIR . ‘/partials/footer.php‘;
That makes the include relative to the file that contains the statement, which stays stable.
A safe guard for optional includes
If a missing include is acceptable, I still want predictable behavior and a log entry.
<?php
declare(strict_types=1);
$path = DIR . ‘/partials/optional-promo.php‘;
if (is_file($path)) {
include $path;
} else {
error_log(‘Optional promo partial missing: ‘ . $path);
}
I prefer this over relying on PHP warnings, because warnings can be suppressed or routed differently across environments.
Include path and why I avoid relying on it
PHP has an include_path setting that influences resolution. In large systems, this becomes hidden coupling. You can spend hours debugging why a file resolved on one machine but not another. Explicit paths keep your system honest.
Case sensitivity: the Windows-to-Linux faceplant
This is a deployment-day classic: your dev machine loads include DIR . ‘/Partials/NavBar.php‘; just fine on a case-insensitive filesystem, and production (Linux) fails because the real file is partials/navbar.php.
If you’re in a mixed environment, I recommend enforcing case correctness in CI (for example by running tests in a Linux container even if your laptop isn’t Linux).
Security and Reliability: Never Include Based on User Input
If there’s one hard rule I want you to remember, it’s this: do not feed raw user input into include/require.
The reason is simple: inclusion executes code. If an attacker can influence which file is included, you’re flirting with local file inclusion (LFI), information disclosure, or worse.
A dangerous pattern (don’t do this)
<?php
declare(strict_types=1);
$page = $_GET[‘page‘] ?? ‘home‘;
include DIR . ‘/pages/‘ . $page . ‘.php‘;
Even if you think you’re safe, attackers will try ../ traversal, unexpected encodings, and edge cases that you did not anticipate.
A safe pattern: explicit whitelist
<?php
declare(strict_types=1);
$page = $_GET[‘page‘] ?? ‘home‘;
$routes = [
‘home‘ => DIR . ‘/pages/home.php‘,
‘pricing‘ => DIR . ‘/pages/pricing.php‘,
‘account‘ => DIR . ‘/pages/account.php‘,
];
if (!arraykeyexists($page, $routes)) {
httpresponsecode(404);
echo ‘Not found‘;
exit;
}
require $routes[$page];
This preserves the convenience of file-based routing while keeping control over what can execute.
Stream wrappers and remote includes: disable the foot-guns
PHP supports stream wrappers (php://, file://, and others), and there’s a configuration setting historically associated with including remote content (allowurlinclude). In real-world production, I treat “include anything but local files in my codebase” as a red flag.
Even if you never touch remote includes directly, a user-controlled include path plus stream wrappers is a nasty combo. The whitelist approach above avoids this entire class of problems.
My “mandatory auth” stance
Authentication and authorization checks should never be “optional.” If you keep them in an included file, make it a require and fail the request if it’s missing. Silent continuation is how you create accidental bypasses.
Performance Reality: What Matters and What Doesn’t
People sometimes ask whether require is “faster” than include. In practice, the performance story looks like this:
includevsrequireperformance differences are not what you feel in real apps.- The big costs are file system I/O, path resolution, and parsing—mitigated heavily by OPcache in typical production setups.
*_oncecan add overhead in include-heavy legacy apps because it does extra bookkeeping.
What I actually measure in production
On modern PHP 8.x deployments with OPcache enabled, the per-request overhead of a handful of includes is usually noise compared to:
- Network calls (databases, APIs)
- Template rendering work
- Serialization/deserialization
- Logging and tracing
Where includes do become a factor is legacy systems with hundreds of small include files per request, especially if OPcache settings are misconfigured or if you’re hitting slow storage.
Practical guidance
- Keep the include graph shallow: fewer, larger files beat dozens of tiny ones.
- Don’t include inside tight loops.
- Prefer autoloaded classes over “include a file full of functions.”
- If you must use many includes, ensure OPcache is enabled and sized correctly.
I’ll also say this plainly: chasing micro-gains by swapping include to require is a distraction. Choose based on correctness and failure behavior.
Traditional Includes vs Modern PHP Composition (2026 Patterns)
I still see older codebases that treat includes as the architecture. It can work, but it’s brittle at scale.
Here’s how I frame it when modernizing:
Modern approach I recommend
—
require ‘db.php‘; that creates globals require a config file that returns an array, then build a client in one place
include ‘helpers.php‘; full of functions in the global namespace Put helpers in namespaced classes/functions, autoloaded via Composer
Single front controller that requires a bootstrap once
include templates that depend on many implicit variables Template renderer function + explicit view model array
include based on $_GET[‘page‘] Router maps routes to handlers explicitly
Composer autoloading is the default for code, not includes
In 2026, if I’m writing new PHP, I treat includes as something I do for:
- Bootstrapping (autoload, container, environment)
- Returning configuration arrays
- Simple “raw PHP template” rendering
Everything else—classes, services, controllers, domain logic—goes through Composer autoloading.
At a high level, I want my application code to look like this:
<?php
declare(strict_types=1);
require DIR . ‘/vendor/autoload.php‘;
require DIR . ‘/bootstrap/app.php‘;
$kernel = new App\Http\Kernel();
$kernel->handleRequest();
And I want my class files to never be manually included.
When “don’t include at all” is the right answer
Here are situations where I recommend stepping away from include/require entirely:
- You’re including “service files” (
db.php,cache.php,mailer.php) just to create globals. - You’re including a bunch of function files and fighting redeclarations.
- You’re including files in different orders to control behavior.
Those are all signals that you want:
- A container (even a minimal one)
- Explicit dependency wiring
- Autoloading with namespaces
Includes can still exist at the boundaries, but they shouldn’t be your architecture.
Practical Scenarios (With Patterns I Actually Use)
This is where the difference between include and require stops being theoretical.
Scenario 1: “Optional feature module” that should never break checkout
Let’s say you have a checkout page, and there’s an optional cross-sell widget. Missing widget file should not take checkout down.
<?php
declare(strict_types=1);
require DIR . ‘/vendor/autoload.php‘;
require DIR . ‘/bootstrap/app.php‘;
// ...checkout logic...
$widgetPath = DIR . ‘/partials/cross-sell.php‘;
if (is_file($widgetPath)) {
include $widgetPath;
} else {
error_log(‘Cross-sell widget missing: ‘ . $widgetPath);
}
The key is that the rest of the request does not rely on that widget to set variables, register handlers, or define functions. It’s truly optional.
Scenario 2: Mandatory invariants (error handling, env, secrets)
Invariants are where require shines. If your app assumes that error reporting, environment variables, or secret loading has already happened, you want to stop if it hasn’t.
<?php
declare(strict_types=1);
require DIR . ‘/bootstrap/runtime.php‘;
require DIR . ‘/bootstrap/secrets.php‘;
// If either file is missing, continuing would be riskier than failing.
I’d rather see a clear failure (and an alert) than quietly run in an unknown state.
Scenario 3: Returning configuration per environment
This is a clean “require returns a value” pattern that I use constantly.
config/app.php:
<?php
declare(strict_types=1);
return [
‘env‘ => getenv(‘APP_ENV‘) ?: ‘production‘,
‘debug‘ => (getenv(‘APP_DEBUG‘) ?: ‘0‘) === ‘1‘,
‘baseurl‘ => getenv(‘APPBASE_URL‘) ?: ‘http://localhost‘,
];
bootstrap/app.php:
<?php
declare(strict_types=1);
$config = require DIR . ‘/../config/app.php‘;
if ($config[‘debug‘]) {
iniset(‘displayerrors‘, ‘1‘);
}
This keeps configuration in plain PHP (fast, expressive), but avoids global variables.
Scenario 4: Rendering templates without implicit variables
Raw PHP templates can be fine, but I don’t like “templates reach into whatever variables happen to exist.” A small renderer makes intent explicit.
<?php
declare(strict_types=1);
function render(string $template, array $data = []): string
{
$path = DIR . ‘/templates/‘ . $template . ‘.php‘;
if (!is_file($path)) {
throw new RuntimeException(‘Template missing: ‘ . $path);
}
ob_start();
extract($data, EXTR_SKIP);
include $path;
return (string) obgetclean();
}
Usage:
<?php
echo render(‘profile‘, [
‘title‘ => ‘Account‘,
‘user‘ => $user,
]);
This still uses include, but now the boundary is controlled:
- Missing templates are treated as real errors (exception)
- Data is passed explicitly
- Output is captured and returned, so you decide where it prints
Note: extract() is convenient but can be abused. I use EXTR_SKIP to avoid overwriting variables unintentionally, and I keep templates “dumb” (no business logic) so the data surface stays small.
Common Pitfalls I See (And How I Avoid Them)
These are the mistakes that keep showing up in reviews and incident postmortems.
1) Making a file “optional” when the code isn’t actually safe without it
Developers sometimes change require to include to fix an outage… and accidentally create a partial failure that turns into something worse.
Example: you include a file that defines is_admin() and later call it unconditionally. If the include fails, you now have a new fatal (“undefined function”), but later in the request, possibly after sending headers or writing partial output.
My fix is to make optionality real:
- Guard inclusion, and
- Guard the usage, or
- Redesign so the missing module results in a safe default
2) Including inside loops
I’ve seen code like:
foreach ($items as $item) {
include DIR . ‘/partials/item-row.php‘;
}
If that template is tiny and cached by OPcache, you might get away with it, but it’s still a smell: you’re doing file operations on every iteration, and you’re hiding dependencies.
If you must do this, keep the included file extremely lightweight and rely on OPcache. Prefer a function call or a component renderer that does not touch the filesystem each iteration.
3) Using extract() without constraints
extract() can overwrite variables or import unexpected keys. If you use it, use EXTRSKIP or EXTRPREFIX_ALL and pass controlled data.
I’ve debugged real issues where $title was unexpectedly changed because a template received [‘title‘ => ...] and the calling scope already had $title in use for something else.
4) Mixing PHP logic and template output unpredictably
If an included template echoes at surprising times, it can break redirects, cookies, or response formats.
My “safe default” is:
- In HTTP handlers, build the response first.
- In templates, echo markup.
- Use output buffering only when you need to capture HTML as a string.
5) Hiding missing files in production
If you suppress warnings or ignore missing optional fragments, you can lose observability.
Even if a fragment is optional, I want to know when it disappears. I log it. In mature systems, I also tag these logs with request IDs and deployment versions so I can correlate “missing template” spikes to a specific deploy.
Deployment and CI: Preventing Missing Includes Before They Hurt
My favorite require vs include discussions are the ones you never have, because you caught the issue before deploy.
Make the artifact complete
If your deployment process can produce a build where some partials aren’t present (like my outage story), the fix isn’t “always use include.” The fix is to ensure the artifact is complete and consistent.
Practical checks I’ve used:
- Build in a clean environment (no untracked local files)
- Create an artifact (tar/zip/image) and deploy that exact artifact everywhere
- Run a smoke check that enumerates expected template/config files
Use php -l and a minimal bootstrap check
A fast sanity check is running lint across your PHP files. It won’t catch missing includes, but it does catch parse errors introduced in templates.
I also like a “bootstrap check” script that runs in CI and verifies mandatory files exist:
vendor/autoload.phppresent- core config files present
- templates directory present
This is boring work, but it prevents boring outages.
Static analysis won’t save you from dynamic includes
Tools can help, but if you build include paths dynamically, you make analysis harder. The more your includes are explicit and path-stable, the more tooling can reason about your code.
Quick Reference Cheat Sheet
If you want the tl;dr that I actually follow:
- Use
requirewhen the script cannot make sense without the file. - Use
includeonly when you are genuinely okay continuing without the file. - For optional includes, prefer
is_file()guards and intentional logging over relying on warnings. - Prefer
requirefor bootstrap + autoload + security invariants. - Prefer config files that
returndata instead of defining globals. - Prefer Composer autoloading for classes instead of manually including class files.
- Use
*_onceas a safety net for legacy code; don’t build new architecture on it.
Final Thoughts
The biggest misconception I see is treating include and require as “two ways to do the same import.” They aren’t. They’re control-flow decisions with failure semantics.
When I’m designing a system for reliability, I want invariants to fail fast and loudly (require), and I want optional experiences to degrade intentionally (include with explicit guards and logs). If you adopt that mental model, you’ll avoid the two extremes that cause the most pain: unnecessary outages caused by optional files, and silent partial failures caused by missing mandatory logic.
If you’re modernizing a codebase, remember the third option: stop including so much. Autoload classes, return config values, and treat includes as a boundary mechanism rather than an architecture.


