Include Paths & Best Practices
Knowing include and require (covered on the Include & Require page) is only half the story. The other half is making sure the path you hand to them actually resolves to the right file — every time, regardless of which script triggered the request or what directory the server happened to be running from. Path bugs are one of the most common "works on my machine" problems in PHP, and almost all of them come down to confusing a relative path with an absolute one.
Relative paths are relative to the working directory, not the file
A beginner's instinct is to write include "../config.php"; and assume PHP resolves .. relative to the file that contains the include statement. It does not. A relative path passed to include/require is resolved relative to the current working directory of the PHP process — which is usually the directory of the script that was originally invoked, not the directory of whichever file is doing the including.
project/lib/loader.php
<?php // Intent: load config.php from the project root, one level up from lib/ include "../config.php";
project/index.php
<?php include "lib/loader.php";
When index.php is run directly, the working directory is project/, so loader.php's "../config.php" actually resolves to one directory above project/ — not to project/config.php as intended. This works by accident if you happen to run loader.php directly from inside lib/, and breaks the moment something else includes it. That inconsistency is exactly the kind of bug that only shows up after deployment, when the entry point or working directory changes.
The reliable fix: __DIR__
PHP provides the magic constant __DIR__, which always evaluates to the absolute path of the directory containing the file it appears in — no matter which script included that file or what the current working directory is. Building include paths with __DIR__ makes them immune to the problem above.
project/lib/loader.php (fixed)
<?php require_once __DIR__ . "/../config.php";
Now __DIR__ inside loader.php always resolves to .../project/lib, so __DIR__ . "/../config.php" always resolves to .../project/config.php, regardless of whether the script was run directly, included from index.php, or included from somewhere three directories deep. The related constant __FILE__ gives you the absolute path of the current file itself (including the filename), which is useful for logging or for deriving __DIR__ manually on very old PHP versions, though in modern code __DIR__ is what you want for directory paths.
Comparing __FILE__ and __DIR__
<?php echo __FILE__; echo "\n"; echo __DIR__;
/var/www/project/lib/loader.php /var/www/project/lib
Why relying on include_path is discouraged
PHP also supports a configuration setting called include_path (set in php.ini, or at runtime with set_include_path()), which defines a list of directories PHP searches through when a plain filename is given to include/require without it resolving directly. In theory, this lets you write include "config.php"; from anywhere and have PHP find it automatically, as long as its directory is listed in include_path.
Relying on include_path (avoid this)
<?php // Assumes "/var/www/project/lib" is already in include_path include "loader.php";
In practice this causes more problems than it solves. include_path is a piece of server configuration, not something checked into your project's source code, so the script's behavior now depends on a setting that lives outside version control. Move the project to a different server, a different hosting plan, or even a different developer's machine with a differently configured php.ini, and includes that relied on include_path can suddenly fail to resolve — with no clue in the codebase itself explaining why.
The path is invisible in the code — you cannot tell where a bare
"loader.php"is expected to come from just by reading the file.It couples your application to server configuration that isn't part of the project, making deployments and onboarding fragile.
It can silently pick up the wrong file if two directories in the search list both happen to contain a file with the same name.
Modern autoloaders (Composer’s PSR-4 autoloading) solve the "find this class/file automatically" problem far more predictably, without touching php.ini at all.
Organizing a project so paths stay predictable
Beyond the mechanics of __DIR__, a well-organized directory structure makes include paths easier to reason about in the first place. A common layout for a small, framework-free PHP project looks like this:
A predictable project layout
project/
├── config.php # database credentials, environment settings
├── index.php # single public entry point
├── includes/
│ ├── header.php
│ ├── footer.php
│ └── functions.php
├── classes/
│ ├── User.php
│ └── Order.php
└── public/
├── css/
└── js/One shared
config.phpat the project root, loaded withrequire_once __DIR__ . "/config.php"from anywhere that needs it.A dedicated
includes/folder for templates and shared snippets, keeping page-specific files short.A
classes/(orsrc/) folder for class definitions, ideally loaded through a Composer autoloader rather than individualrequirestatements once the project grows.Static assets kept out of the PHP folders entirely, under a
public/directory the web server points at directly.
With a layout like this, every include path can be expressed consistently as __DIR__ plus a fixed relative offset, because the directory structure itself is stable even as individual files come and go.