Categories
Code Programming WordPress

__DIR__ vs dirname( __FILE__ )

Calling a constant should always be faster than a function call, right? PHP contains two different ways to get the directory that a file is currently in. __DIR__ is a magic constant added to PHP in 5.3. The official PHP documentation specifically states: “This is equivalent to dirname(__FILE__).” Equivalent in return doesn’t necessarily mean equivalent in performance though, so I decided to test the performance of both accross a couple of variables.

Testing Methodology

When running lots of tests, I’ve found that travis-ci can be a big helper. You can define the matrix of the tests you want to run as your testing matrix and then use the results. So I setup a repo for my tests. The repo contains four main pieces:

  1. A file generator which creates the code I’ll actually run the performance test on.
  2. A test running script which runs the actual tests.
  3. The travis.yml file to define my tests matrix
  4. Files used for the actual test. This is not linked, there are 400,000 files. The generator shows them off.

My test calls the function I am looking for 100,000 each. One run has all the files in 1 directory, and the other has one file per directory. I wanted to rule out the possibility that a single directory could affect this call.

I ran this test on six version of PHP: 5.6.40, 7.0.33, 7.1.27, 7.2.15, 7.3.9 and 7.4-dev. Each test did 650 runs and I looked at the user time for each of those runs. This means that I called both __dir__ and dirname( __file__ ) 130,000,000 times each. I then took the times for each of these runs and looked at that maximum (slowest) run for each and the 95% time ( the average between the 618th and 619th slowest) to rule out any extreme cases. Overall, the results between maximum and 95% are similar.

User is the amount of CPU time spent in user-mode code (outside the kernel) within the process. This is only actual CPU time used in executing the process. Other processes and time the process spends blocked do not count towards this figure.

Stack Overflow

__DIR__ vs dirname( __FILE__) Test Results

95% performance

Script5.67.07.17.27.37.4
dir ( 1 folder)1.42.762.082.512.271.3615
dir ( many folders)1.382.292.552.36152.651.57
dirname( 1 folder)1.58152.272.74153.242.411.5215
dirname( many folders)1.682.292.08153.292.68151.87

Overall, the results show that __dir__ is generally faster, but it’s rarely much faster. Consider that in the slowest run ( using PHP 7.2 and calling dirname( __FILE__ ) on multiple folders), each call took 0.0000329 seconds. The fastest run was 2 hundred-thousandths of a second faster. This is such a micro optimization that except under extreme scale, it’s unlikely you will ever notice a difference. That said, under most versions of PHP, __DIR__ is faster.

So: __dir__ or dirname?

At the end of the day, the performance of __DIR__ is ever so slightly better, but more importantly I think it’s clearer and easier to read. So I’m on team __dir__, but the performance is only a bonus.

If you have a different thought, or think that my testing methodology could be improved, please let me know in the comments below.

3 replies on “__DIR__ vs dirname( __FILE__ )”

Hey Jorbin,

Great to see a curious mind at work!

I’m afraid your testing methodology is off, though, and the results you are getting are not measuring what you think they are.

The thing is, both `__DIR__` and `__FILE__` are compile-time constants. After the first parsing of the PHP file, the PHP byte code will land in PHP’s op-cache, so looping here to measure a bigger slice of time basically measures everything _but_ these constants. The first file will just be `return ;`, and the second one will be `return dirname( );`.

The main difference is “a string used as-is” VS “a string processed through a function to split off one component”.

BUT, then again, it’s not that easy, because PHP also uses compile-time optimizations. So, as it knows that `__FILE__` is a compile-time constant, some versions of PHP even optimize away the `dirname()` processing, as the result doesn’t change dynamically (the op-cache is based on filesystem location).

So in the end, for some versions, you really only test `return ;` VS `return ;`.

So where do the differences come from, then? It is hard to tell without doing actual profiling, but my guess would be that a large part of the difference might actually come from shuffling memory around, as the strings for the `dirname` tests are all a bit longer than the strings for the `dir` test…

Maybe the above makes you curious enough to dive even deeper, so looking forward to the next iteration! 😉

Cheers,
Alain

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.