Sunday, 5 October 2014

PHP: include paths... it gets worse...

G'day:
This follows on from my article from an hour or so ago "PHP: include paths are relative to the current working directory". The situation there was daft but at least had a precedent in other languages.

But this? This beggar's belief.



Over and above the weirdo behaviour I saw in the previous article, I had been seeing other behaviour which just didn't add up. And I could not work out WTF was going on, until just now.

For this experiment, I have these files:

include/    
    working/
        actual/
            callMe2.php
            incExistsInActualAndWorking.php
            incExistsOnlyInActual
        incExistsInActualAndWorking.php

And the files are:

<?php
// callMe2.php
printf("Working directory: %s\n\n\n", getcwd());
echo "including incExistsOnlyInActual.php\n";
include "incExistsOnlyInActual.php";

echo "\n\n";
echo "including ./incExistsOnlyInActual.php\n";
include "./incExistsOnlyInActual.php";

echo "\n\n================================\n\n";

echo "including incExistsInActualAndWorking.php\n";
include "incExistsInActualAndWorking.php";

echo "\n\n";
echo "including ./incExistsInActualAndWorking.php\n";
include "./incExistsInActualAndWorking.php";


<?php
// incExistsOnlyInActual.php
echo "included actual/incExistsOnlyInActual.php\n\n";


<?php
// actual/incExistsInActualAndWorking.php
echo "included actual/incExistsInActualAndWorking.php\n\n";


<?php
// working/incExistsInActualAndWorking.php
echo "included working/incExistsInActualAndWorking.php\n\n";

When I run callMe2.php from the working directory, I get this:

C:\include\working>php actual\callMe2.php
Working directory: C:\include\working

including incExistsOnlyInActual.php
included actual/incExistsOnlyInActual.php


including ./incExistsOnlyInActual.php
PHP Warning:  include(./incExistsOnlyInActual.php): failed to open stream: No such file or directory in C:\include\working\actual\callMe2.php on line 9

Warning: include(./incExistsOnlyInActual.php): failed to open stream: No such file or directory in C:\include\working\actual\callMe2.php on line 9
PHP Warning:  include(): Failed opening './incExistsOnlyInActual.php' for inclusion (include_path='.;C:\php\pear') in C:\include\working\actual\callMe2.php on line 9

Warning: include(): Failed opening './incExistsOnlyInActual.php' for inclusion (include_path='.;C:\php\pear') in C:\include\working\actual\callMe2.php on line 9

================================

including incExistsInActualAndWorking.php
included working/incExistsInActualAndWorking.php


including ./incExistsInActualAndWorking.php
included working/incExistsInActualAndWorking.php


C:\include\working>

What?

A reminder: ./incExistsOnlyInActual.php and incExistsOnlyInActual.php are relative references to exactly the same file "." just means "the current dir". So one is an explicit reference to the current dir, the other is implicit. The canonical path for both of these references is the same.

Yet... PHP handles them differently. Without the ./, PHP seems to do this:

  • looks in the working directory;
  • if the file is not there, looks in the directory the file making the include call is in.

It would make more sense if those two look-ups were reversed, but there's some logic there.

However if the file reference does have the "./", then PHP only looks in the working directory (not the current directory, I hasten to add).

I can understand one of these behaviours or the other. But not two different bloody behaviours for two different ways of referencing a relative path. That's just fuckin' stupid.

What on earth are you thinking, PHP? It's either just white noise, or elevator music1, I think.

Grrrr.

--
Adam



1 I am actually finding myself thinking of this clip from Dawn of the Dead when I write that.