Stop Passing File Paths as Strings: A Quick Introduction to SplFileInfo
Scott Keck-Warren • June 19, 2026
A while back, I was building a small file processing script. It took an upload directory, looped through the files, and did different things depending on the file type. It's most likely something you've done yourself.
The function signature looked like this:
function processFile(string $path): void
And somewhere deep in that function, I was checking the extension like this:
$ext = substr($path, strrpos($path, '.') + 1);
It worked fine in testing. Then it hit a file with no extension, strrpos returned false, the math went sideways, and I ended up with $ext being the entire path. The script tried to match it against 'jpg' and silently did nothing. Hundreds of files got skipped, no error, no log entry, and we didn't catch it for two days.
I was passing a raw string around and extracting structured information from it by hand. PHP has a class specifically designed to avoid that, and I wasn't using it.
What SplFileInfo Actually Is
SplFileInfo is a class built into PHP's Standard Library that wraps a file path and gives you a set of typed methods for working with it. No Composer package, no configuration, it's just there.
Think of it like the difference between storing a date as a string ("2026-06-19") versus using a DateTimeImmutable object. With the string, you end up parsing it manually every time you need a piece of it, but with the object, you "just"call a method. It's the same idea with file paths.
Instead of doing string gymnastics to pull out an extension or filename, you create a SplFileInfo object and ask it directly.
$file = new SplFileInfo('/uploads/photo.jpg');
$file->getExtension(); // "jpg"
$file->getBasename(); // "photo.jpg"
$file->getFilename(); // "photo.jpg"
$file->getPath(); // "/uploads"
$file->isFile(); // true
$file->isDir(); // false
$file->getSize(); // file size in bytes
$file->getMTime(); // last modified timestamp
Every one of these is typed and consistent, and because you're calling a method, you're not doing arithmetic on a string (yuk).
The Real Benefit: Type Hints
The bigger payoff is in your function signatures. Compare these two versions of the same functionality:
// Version 1: string path
function processUpload(string $path): void
{
$ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
$size = filesize($path);
// ...
}
// Version 2: SplFileInfo
function processUpload(SplFileInfo $file): void
{
$ext = strtolower($file->getExtension());
$size = $file->getSize();
// ...
}
The first version accepts any string, but instead of a path, you could pass it a URL, a database column name, or an empty string, and PHP won't complain until something blows up at runtime. The second version only accepts a SplFileInfo object, so the type system catches the wrong input before the function even runs.
When a teammate reads that second signature, they know immediately that this function works with a file. They don't need to read the body to figure out what format $path is supposed to be.
A Practical Example: Processing Uploaded Files
For file uploads, I keep validation in its own function, and the type hint makes the contract explicit.
function validateUpload(SplFileInfo $file): bool
{
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
if (!$file->isFile()) {
return false;
}
if (!in_array(strtolower($file->getExtension()), $allowed)) {
return false;
}
return !($file->getSize() > 5 * 1024 * 1024); // 5MB limit
}
// Usage
$file = new SplFileInfo($_FILES['avatar']['tmp_name']);
if (validateUpload($file)) {
// process it
}
Compare that to passing $_FILES['avatar']['tmp_name'] as a raw string and then calling pathinfo() and filesize() inside the function. The SplFileInfo version is clearer about what it needs and what it does with it.
Iterating a Directory
SplFileInfo also shows up naturally when you use PHP's DirectoryIterator. Each item you get back from the iterator is already a SplFileInfo object, so you get all the same methods without constructing anything yourself.
$directory = new RecursiveDirectoryIterator(
'vendor',
RecursiveDirectoryIterator::SKIP_DOTS // Skip . and .. automatically
);
foreach ($directory as $file) {
if ($file->isFile() && $file->getExtension() === 'csv') {
echo $file->getBasename() . ' (' . $file->getSize() . " bytes)\n";
}
}
A Few Things to Keep in Mind
SplFileInfo does not check whether the file exists when you construct it. You can create new SplFileInfo('/some/path/that/doesnt/exist.txt') with no error. Methods like getSize() and isFile() will just return false or throw if the file isn't there, so you still need to check before calling those.
And getExtension() returns the extension without the dot, so you get "jpg", not ".jpg".
Stop Passing File Paths as Strings
Next time you find yourself reaching for pathinfo(), basename(), or filesize() on a raw string, take a second and reach for SplFileInfo instead. Wrap the path once, use the methods, and type-hint your functions properly. Your teammates will know what the function expects, your IDE will give you better autocomplete, and you won't spend two days wondering why your file processing script silently skipped half the uploads.