dirname

Returns the parent directory of a path, optionally going up several levels.

Signature
dirname(string $path, int $levels = 1): string
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$pathstringA path. On Windows both / and \ act as directory separators; everywhere else only / does.
$levelsoptionalint= 1The number of parent directories to go up. Must be an integer greater than 0.

Return value

stringThe path of the parent directory. If the path has no separators, a dot is returned. If the path is the root, the root is returned.

Errors

Throws a ValueError when levels is less than 1.

dirname() chops the last component off a path string. Like basename(), it is pure string work — it never checks that the directory exists and never emits a warning.

When to reach for it

The classic use is locating your project root from a file inside it: dirname(__DIR__, 2) reads far better than three stacked calls or a chain of /.. segments that realpath() then has to untangle. It is also how you find the parent of a target path before mkdir()-ing it, and how you build sibling paths next to a config file.

Prefer __DIR__ over dirname(__FILE__); the magic constant is resolved at compile time and does the same thing.

What trips people up

A bare filename has no directory, so dirname("file.txt") is "." — not an empty string. Concatenating blindly gives "./file.txt", which usually still works but looks wrong in logs and breaks string comparisons.

At the root the function is a fixed point: dirname("/") is "/", and asking for more levels than the path has also lands on "/". A loop that climbs by calling dirname() until it "runs out" never terminates — compare against the previous value instead.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Find the project root from a bootstrap file with dirname(__DIR__, 2)
  • Create a target file's parent directory with mkdir(dirname($path), 0775, true)
  • Build a sibling path such as app.local.ini next to an already-known config file
  • Group a list of file paths by the folder they live in

Frequently asked questions

What is the difference between dirname(__FILE__) and __DIR__?

They produce the same string, but __DIR__ is resolved when the file is compiled and costs nothing at runtime. Use __DIR__, and use dirname(__DIR__, 2) when you need to climb from there.

Does dirname check that the directory exists?

No. It is a string operation only, so it happily returns a parent path for a file that was never created. Use is_dir() if you need to know whether the result is real.

How do I get the directory two levels up?

Pass 2 as the second argument: dirname($path, 2). It is equivalent to dirname(dirname($path)) but clearer and slightly faster.

More examples

Climbing several levels at once

Levels 1 to 4 walk up to /srv/app/src/Http, /srv/app/src, /srv/app and /srv. Asking for 10 levels does not error — it clamps at the root and returns /. That clamping is why you cannot detect "I have gone too far" from the return value alone.

Example · php
<?php
$file = "/srv/app/src/Http/Controller.php";

for ($i = 1; $i <= 4; $i++) {
    echo $i, ": ", dirname($file, $i), "\n";
}

echo "way too far: ", dirname($file, 10), "\n";

Building sibling and cousin paths

The first path stays in the same folder, the second steps up two levels to /etc/myapp and then down into logs. The final var_dump is the trap: a relative filename with no directory yields a single dot, so concatenation produces ./app.local.ini rather than a bare name.

Example · php
<?php
$config = "/etc/myapp/conf.d/app.ini";

$sibling = dirname($config) . "/app.local.ini";
$logs    = dirname($config, 2) . "/logs";

echo $sibling, "\n";
echo $logs, "\n";

var_dump(dirname("app.ini"));   // string(1) "."

Creating the parent directory before writing

dirname() gives cache/http, and mkdir()'s third argument creates both levels in one call. This is the standard guard before file_put_contents(), which — like copy() — fails if the parent directory is missing rather than creating it.

Example · php
<?php
$target = "cache/http/page-1.html";
$dir = dirname($target);

if (!is_dir($dir)) {
    mkdir($dir, 0775, true);
}
file_put_contents($target, "<h1>hello</h1>");

echo $dir, " -> ", file_get_contents($target), "\n";

unlink($target);
rmdir("cache/http");
rmdir("cache");

Discussion

  • Be the first to comment on this lesson.