Filesystem path APIs

php.internals

Niels Dossche

2 years ago
Hi internals I'd like to start a pre-RFC discussion about filesystem path APIs in PHP. The reason I bring this up is because of this recent feature request: https://github.com/php/php-src/issues/11258 The feature request is about the following: We already have some functions to work with paths in PHP, e.g. basename, dirname, realpath. We do not have some common path APIs that you can find in other languages like: path_join to join paths and path_normalize to normalize paths. As not everyone may be familiar with such functions, I'll explain them briefly. **Proposed Functions:** 1. path_join(string... $components): string; This function concatenates the components with a / (or \ on Windows) between them and normalizes the path. If the resulting path is empty then it'll return "." to indicate the current directory. You may be wondering "Isn't this just implode?". Not really, it normalizes the path too, which means that components like "." are removed from the path, redundant slashes are removed, and if there are ".." components then they remove the previous component from the path. It's also not the same thing as calling realpath after doing implode: realpath would not work for non-existent paths and it would allow escaping from the root. To demo the root escape problem: path_join("..", "foo"); yields "foo" Whereas realpath("../foo"); yields the absolute path of the "foo" file one directory up. Note: This function does not do any I/O. 2. path_normalize(string $path): string; This function only does the normalization part described above. Note: This function also does not do any I/O. **Examples:** ```php // Example usage of path_join $result = path_join('dir1', 'dir2', '..', 'file.txt'); // Resolves to 'dir1/file.txt' // Example usage of path_normalize $normalizedPath = path_normalize('dir1/../dir2'); // Resolves to 'dir2' ``` I think these would be great additions to PHP as working with paths and files is a core part of any programming language. Furthermore, languages like Python and runtimes like Node.JS allow to join and normalize paths that are not native to the operating system PHP is running on. E.g. it's possible to create a Posix-style path (what is used on Linux, macOS, BSD etc) on a Windows system. This is sometimes necessary in order to construct a path to access a remote file on a Linux server to just give an example. In PHP we could add functions like (just to give an example): \Path\Windows\join for Windows paths \Path\Posix\join for Linux/macOS/Posix paths \Path\join that automatically chooses one of the above depending on what operating system PHP runs on. Similar approach for path_normalize. There could be OOP-style alternatives too, e.g. Rust has a PathBuf struct with methods that are used to build paths. However if we were to choose this route then we need to be aware that interoperability with existing filesystem functions would be much harder because they all work directly with strings at the moment. What do you think? Kind regards Niels

Ayesh - PHP.Watch

2 years ago
> > There could be OOP-style alternatives too, e.g. Rust has a PathBuf struct with methods that are used to build paths. > However if we were to choose this route then we need to be aware that interoperability with existing filesystem functions would be much harder because they all work directly with strings at the moment. >
I think we really could use such an API. I would have liked a more OOP-style approach, because it can impactfully "consolidate" various functions into one. I really like NodeJS Path class (https://nodejs.org/api/path.html), which I think have done a really nice job at making it simple while being quite versatile even for remote system paths. In PHP land, the now-abandoned path-util (https://packagist.org/packages/webmozart/path-util) library also had an intuitive API.

Jeffrey Dafoe

2 years ago
> The feature request is about the following: > We already have some functions to work with paths in PHP, e.g. basename, > dirname, realpath. > We do not have some common path APIs that you can find in other languages > like: path_join to join paths and path_normalize to normalize paths.
...
> What do you think?
That would be a welcome addition in my book. -Jeff

Max Semenik

2 years ago
On Wed, Dec 6, 2023 at 10:20 PM Niels Dossche <dossche.niels@gmail.com> wrote:
> Hi internals > > I'd like to start a pre-RFC discussion about filesystem path APIs in PHP. > The reason I bring this up is because of this recent feature request: > https://github.com/php/php-src/issues/11258 > > The feature request is about the following: > We already have some functions to work with paths in PHP, e.g. basename, > dirname, realpath. > We do not have some common path APIs that you can find in other languages > like: path_join to join paths and path_normalize to normalize paths. >
We have a lot of commonly used functionality that's successfully fulfilled by Composer packages - does this really have to be core functionality? I understand the argument about batteries included, but across mainstream languages you can always find examples of something that sounds like it should really be there, but it isn't.
-- Best regards, Max Semenik

Lanre Waju

2 years ago
So your suggestion for simple file stuff is to download composer? On 2023-12-08 1:43 a.m., Max Semenik wrote:

Max Semenik

2 years ago
On Fri, Dec 8, 2023 at 11:45 AM Lanre Waju <lanre@online-presence.ca> wrote:
> So your suggestion for simple file stuff is to download composer? >
Not necessarily, but I'd like to have more discussion of pros and cons.
-- Best regards, Max Semenik

Pierre Joye

2 years ago
On Fri, Dec 8, 2023, 3:44 PM Max Semenik <maxsem.wiki@gmail.com> wrote:
> On Wed, Dec 6, 2023 at 10:20 PM Niels Dossche <dossche.niels@gmail.com> > wrote: > > > Hi internals > > > > I'd like to start a pre-RFC discussion about filesystem path APIs in PHP. > > The reason I bring this up is because of this recent feature request: > > https://github.com/php/php-src/issues/11258 > > > > The feature request is about the following: > > We already have some functions to work with paths in PHP, e.g. basename, > > dirname, realpath. > > We do not have some common path APIs that you can find in other languages > > like: path_join to join paths and path_normalize to normalize paths. > > > > We have a lot of commonly used functionality that's successfully fulfilled > by Composer packages - does this really have to be core functionality? >
if any of them could be a easy win, relative path resolver without checking its existence would be one. It is available internally but the existence check option is not exposed.

Dusk

2 years ago
On Dec 8, 2023, at 09:13, Pierre Joye <pierre.php@gmail.com> wrote:
> if any of them could be a easy win, relative path resolver without checking > its existence would be one. It is available internally but the existence > check option is not exposed.
Are you thinking of realpath()? That also expands symbolic links, which wouldn't be desirable for abstract path manipulation.

David CARLIER

2 years ago
Hi Niels, On Wed, 6 Dec 2023 at 19:20, Niels Dossche <dossche.niels@gmail.com> wrote:
> Hi internals > > I'd like to start a pre-RFC discussion about filesystem path APIs in PHP. > The reason I bring this up is because of this recent feature request: > https://github.com/php/php-src/issues/11258 > > The feature request is about the following: > We already have some functions to work with paths in PHP, e.g. basename, > dirname, realpath. > We do not have some common path APIs that you can find in other languages > like: path_join to join paths and path_normalize to normalize paths. > > As not everyone may be familiar with such functions, I'll explain them > briefly. > > **Proposed Functions:** > > 1. path_join(string... $components): string; > This function concatenates the components with a / (or \ on Windows) > between them and normalizes the path. > If the resulting path is empty then it'll return "." to indicate the > current directory. > You may be wondering "Isn't this just implode?". Not really, it normalizes > the path too, which means that components like "." are removed from the > path, redundant slashes are removed, and if there are ".." components then > they remove the previous component from the path. > > It's also not the same thing as calling realpath after doing implode: > realpath would not work for non-existent paths and it would allow escaping > from the root. > To demo the root escape problem: > path_join("..", "foo"); yields "foo" > Whereas realpath("../foo"); yields the absolute path of the "foo" file one > directory up. > > Note: This function does not do any I/O. > > 2. path_normalize(string $path): string; > > This function only does the normalization part described above. > Note: This function also does not do any I/O. > > **Examples:** > > ```php > // Example usage of path_join > $result = path_join('dir1', 'dir2', '..', 'file.txt'); // Resolves to > 'dir1/file.txt' > > // Example usage of path_normalize > $normalizedPath = path_normalize('dir1/../dir2'); // Resolves to 'dir2' > ``` > > > I think these would be great additions to PHP as working with paths and > files is a core part of any programming language. > > > Seems like it, is there an argument to be made to, let's say, in the
performance side ?

Niels Dossche

2 years ago
Hi David On 08/12/2023 10:08, David CARLIER wrote:
> I think these would be great additions to PHP as working with paths and files is a core part of any programming language. > > > Seems like it, is there an argument to be made to, let's say, in the performance side ? 
A native implementation is going to be faster than an implementation in userspace. However, I don't think that matters because the performance is likely dominated by the I/O you do after constructing a path. You'd need to construct a large number of paths before you notice anything I guess. Cheers Niels

David CARLIER

2 years ago
On Fri, 8 Dec 2023 at 16:10, Niels Dossche <dossche.niels@gmail.com> wrote:
> Hi David > > On 08/12/2023 10:08, David CARLIER wrote: > > I think these would be great additions to PHP as working with paths > and files is a core part of any programming language. > > > > > > Seems like it, is there an argument to be made to, let's say, in the > performance side ? > > A native implementation is going to be faster than an implementation in > userspace. > However, I don't think that matters because the performance is likely > dominated by the I/O you do after constructing a path. > You'd need to construct a large number of paths before you notice anything > I guess. > > Cheers > Niels >
Very true, so what would be the argument beside having those as "builtins" as opposed to external components ?

Niels Dossche

2 years ago
On 12/9/23 10:40, David CARLIER wrote:
> On Fri, 8 Dec 2023 at 16:10, Niels Dossche <dossche.niels@gmail.com> wrote: > >> Hi David >> >> On 08/12/2023 10:08, David CARLIER wrote: >>> I think these would be great additions to PHP as working with paths >> and files is a core part of any programming language. >>> >>> >>> Seems like it, is there an argument to be made to, let's say, in the >> performance side ? >> >> A native implementation is going to be faster than an implementation in >> userspace. >> However, I don't think that matters because the performance is likely >> dominated by the I/O you do after constructing a path. >> You'd need to construct a large number of paths before you notice anything >> I guess. >> >> Cheers >> Niels >> > > Very true, so what would be the argument beside having those as "builtins" > as opposed to external components ? >
Mainly for convenience reasons and a correct implementation provided by PHP. Many functions in PHP are not strictly necessary because they can be implemented in userland. They're only there for convenience reasons. Where to draw the line is difficult. To me they complement the realpath(), dirname(), basename() functions.

Erick de Azevedo Lima

2 years ago
I'm in favor for this. I think that, since you already have a built-in file API, adding useful functions is always good. I use *\str_starts_with* and *\str_ends_with* a lot in my code. In Laravel, which is the most used Framework these days, you have the \Illuminate\Supports\Str::startsWith and \Illuminate\Supports\Str::endsWith, but it did stop the implementation of those functions in the core and I'm glad for it. Best regards, Erick Em sáb., 9 de dez. de 2023 às 13:21, Niels Dossche <dossche.niels@gmail.com> escreveu: