martedì 21 febbraio 2017

My, myself and PHP namespaces...

I'm starting to hate PHP with a passion.
I don't like its syntax, that I find often quite odd. The "foreach" loop is an example, I like much more the Perl or Java like idiom.
Another feature I'm trying to adapt myself to, and that incresead my hate for this language, is namespace.
The namespace definition is awkward: as first it looks like Perl's or Java's package, but it something really much orrible.
While imposing a filesystem layout (similar to Perl or Java), PHP namespaces does not provide a quick way to isolate code, or better, they isolate too much code at a time.
Let's start from the end: consider a class defined in a namespace as follows

namespace NS1\NS2\NS3;

class Foo { .. }


and now the code that should use it

use NS1\NS2\NS3;
$foo = new NS3\Foo();

Yes, you still need to partially qualify the simbol name. This is due to the fact that "use" without an alias argument is equivalent to aliasing the last part of the namespace, that is the two following lines are the same:


use NS1\NS2\NS3;
use use NS1\NS2\NS3 as NS3;

So in order to reference your symbols without any namespace prefix you have to use them all, that is:

use NS1\NS2\NS3\Foo as Foo;
$foo = new Foo();


I clearly don't get the point of using the above in a productive way: namespaces are a common way to avoid name clashing, and therefore they willc contain a set of related objects (I mean, symbols), so why would I need to use them one at a time?

Luckily (or stupidly), since PHP 7 it is possible to import a namespace the way Perl does, that is:

use NS1\NS2\NS3\{ Foo, Bar, Baz} ;

that is the same as

use NS1\NS2\NS3\Foo as Foo;
use NS1\NS2\NS3\Bar as Bar;
use NS1\NS2\NS3\Baz as Baz;

and that allows for the usage of symbol relative name (I mean, really relative name).

The syntax seems to me a crappy copy of the C++ namespace one, except that the latter has an easy way to reference relatively all symbols in an used namespace.

Now, another ugly detail of the PHP namespaces is that every class referenced within a namespace has to belong to the namespace itself or an used namespace. Why is this ugly? Because of the following:


class Logger { ... }

namespace NS1;
class Foo{
  public function __construct(){
    $this->logger = new \Logger();
    ...
  }
}


As you can see, since the Logger class does not belong to any namespace (let's say it belongs to the "main" namespace), it has to be refenced by a leading slash, that is a way to indicate the "main namespace". This is pretty much ugly because PHP could be smart enough to figure out when a symbol is found in the current and used namespaces, and if it is not it can search for it in the "\" main namespace.
Moreover, the above kindof syntax, makes it very hard to refactor existing code into namespaces; suppose you want to move the Logger class into its own namespace: you have to (i) place it into a namespace, (ii) use such namespace and (iii) remove each call to the main "\" namespace as follows

// (i)
namespace Log;

class Logger { ... }

namespace NS1;
// (ii)
use Log\{ Logger };

class Foo{
  public function __construct(){
    // (iii)
   $this->logger = new Logger();
   ...
 }
}


but step (iii) could have been removed if the original call to the Logger-in-main-namespace had been avoided. Think about Perl and its main:: package (pretty much the same as a PHP namespace), that can be omissed if not necessary:

my $x = "hello"; say $x;
$main::x = "hello"; say $x;


Last but not least: the choice of the backslash is terrible to me!
It reminds me the package separator used in Perl 4: $main'x ...
While I accept that a double colon is not optimal, due to some difficulties in editors to render it properly without any confusion with the switch C++ statement, I take it for granted it is a better established approach and makes it a lot more visible the separation.

Nessun commento: