views:

286

answers:

7

As far as I can tell, the only reason we have namespacing in PHP is to fix the problem of classes (+ functions & constants) clashing with others classes of the same name.

The problem is that most frameworks setup their autoload and filesystem hierarchy to reflect the names of the classes. And no-one actually require()s or include()s files anymore.

So how does namespacing help this any? Either the class is loaded based off of it's name:

new Zend_Db_Table_Rowset_Abstract;

or off it's namespace

new Zend\Db\Table\Rowset\Abstract;

Either way I am stuck with only being able to create one class with this name.

/var/www/public/Zend/Db/Table/Rowset/Abstract.php

UPDATE I'm not sure I'm getting the point across.

Even if I created two files with the same class Zend\Db\Table\Rowset\Abstract in them I still couldn't use them together since they both claim the same namespace. I would have to change their namespace names which is what we already do!

This leaves me to belive that the only use for namespaces is function names. Now we can finally have three functions all named the same thing!

Or wait, I forgot you can't do that either since each requires the namespace prefix!

a\myfunction();
b\myfunction();
c\myfunction();

Taking ircmaxell's example:

$model = new \Application\Model\User;
$controller = new \Application\Controller\User;

How is that any different than without?

$model = new Application_Model_User;
$controller = new Application_Controller_User;

This is also a neat sounding feature - but what does it truly do for us?

use \Application\Model\User as UserModel;
use \Application\Controller\User as UserController;

$foo = new UserModel;
$bar = new UserController;

Now you cannot have a class named 'UserModel' since you have a namespace setting for that term. You also still cannot have two classes named under the same alias.

I guess the good thing is that you can rename the long Zend_Db_Table_Rowset_Abstract

use Zend_Db_Table_Rowset_Abstract as RowAbstract;

leading to developer confusion about where the non-existent class "RowAbstract" is defined and coming from in the system.

+1  A: 

Are you really trying to create a new class called Zend_Db_Table_Rowset_Abstract?

The more likely scenario is that you have a local class called something common like Date, Project, User, or something similar or you have a framework that already has those classes. By having namespaces, there shouldn't be any collisions.

In web2project, we've just added namespace support in v2.0 (but we don't require PHP 5.3) because our classes - like Date, DBQuery, Mail, and a few others - collided with things pretty easily. While we don't have an intention to add an external framework to the system, someone else could pretty easily if they wanted.

Are there less verbose ways of solving the problem? Potentially.. but this worked in the Java world with their piles of libraries, so it's not all new space.

CaseySoftware
this doesn't really answer the problem stated. With, or without name spaces, you can't autoload two files named "mail".
Xeoncross
But *with* namespaces, they likely wouldn't be named "Mail" by itself. There's a Framework Interoperability Group - I lurk on the list - which lays out strategies for making sure it doesn't happen among symfony, Cake, Lithium, Zend Framework, PEAR, and a few other big players. Even Drupal and WordPress have been invited to participate.
CaseySoftware
@CaseySoftware Good point - namespaces force the use of prefixes while standard class names only need prefixes if they are trying to avoid clashes. Frameworks working to ensure interoperability is also a good step - although most frameworks are so different that it would be hard to mix them. Only library collections like Zend or Flourish would benefit from this.
Xeoncross
+1  A: 

Perhaps if you broaden your view a little :)

"As far as I can tell, the only reason we have namespacing in PHP is to fix the problem of classes (+ functions & constants) clashing with others classes of the same name." - yes this is a huge issue which has caused problems for many years in every language that doesn't have namespaces - everybody makes a class Database, Date, URL etc and this fixes it :)

"The problem is that most frameworks setup their autoload and filesystem hierarchy to reflect the names of the classes. And no-one actually require()s or include()s files anymore." - well actually they do, often, just because some common frameworks have had to come up with practises to work around a lack of namespaces, doesn't mean those work arounds or hacks should null and void the 'real' fix to the issue for all :)

follow?

nathan
1) I'm afraid it doesn't. With namespaces you can now call your class Database - *but just like we have been doing along* - you must prefix it with something to prevent clashes (\name\database vs name_database).
Xeoncross
... \name\database is universal, name_database is a weak implementation specific hack because namespaces weren't around. with namespaces *everybody* can be compatible, not just people who happen to follow certain framework practises.
nathan
Good point. However, this is a question about projects with an autoloader that base class names off of matching file paths (almost everyone) and they all use this "hack". So this is more about the *semantic* value than actual value.
Xeoncross
+2  A: 

It's probably not worth it to use namespaces unless you have a big project with multiple developers. I would even argue namespaces are overrated.

For example, in Java (since few people use namespaces yet in PHP I couldn't find any similar examples). These are the choices that come up for List in my IDE (Eclipse):

java.util.List
com.ibm.toad.utils.Strings.List
com.ibm.ws.objectManager.List
com.ibm.ws.webcontainer.util.List
java.awt.List

In this case, I don't really see why they couldn't have just kept java.util.List as the only List, and for example renamed java.awt.List to ScrollingList, which actually describes what it is, makes it more obvious that it is a GUI element, and avoids the collision. I would rather type out a longer and more descriptive class name than have to deal with that.

As for one of the above posters, if everyone in your team is making a class called Database perhaps you need to do some design discussion and use only one Database class instead of shoving each person's personal duplicate into a namespace.

Lotus Notes
Seriously, PHP is a scripting language after all - you can't afford the added load of even 1 superfluous class just because you're team doesn't want to properly design your codebase.
Xeoncross
+6  A: 

Actually, you can create more than one class with the same name

Suppose you have 2 classes:

\Application\Controller\User

and

\Application\Model\User

You couldn't import both into the same file without aliasing one, but you still can define both the same way:

$model = new \Application\Model\User;
$controller = new \Application\Controller\User;

Plus you can import and alias:

use \Application\Model\User as UserModel;
use \Application\Controller\User as UserController;

$foo = new UserModel;
$bar = new UserController;

So it really is quite powerful, as it does let you name your classes however you want (and reference them by arbitrary names inside your code). The only rules are reserved keywords... See: http://www.php.net/manual/en/language.namespaces.importing.php

ircmaxell
I shutter to think about what this is going to do to the application scope of some projects. Some new programmer is going to leave namespace aliases all over the project because he doesn't want to type the full name. xD
Xeoncross
@Xeoncross: actually using aliases is a good idea, because it makes code shorter, easier to read, allows you to give descriptive names and allows you to swap classes by replacing **one** occurence of the class you want to swap. In languages that have aliases, this is done all the time and frankly, it's a helpful feature. It is not much of a hassle to actually take the time to read the header of a file, where such declarations are made. It's definitely less chaotic than global constants or functions imported through include statements.
back2dos
+3  A: 

In your example Zend framework, you can throw namespace Zend; at the top of each class file, remove the Zend_ prefix from all of your classes and functions, and you (mostly) don't need to worry about name collisions ever again. Your Zend_Date class can be renamed as just Date without interfering with the built-in date classes. Meanwhile, users of your framework can write Zend\Date instead of Zend_Date which isn't any longer to type, but they now have several other options for accessing the class more easily.

too much php
So, in the file that I define each class or function I don't need to add the `Zend_` prefix - but now over the rest of the file I have to add `\name\...` before each function or class? I don't think that is a good trade. On another note, this is the best namespace summery so far. :)
Xeoncross
You only need to add `\name\...` if you were referencing a *class* outside of your Zend framework, and then it's just a case of throwing a single `\ ` on the front (`throw new \Exception` etc). http://php.net/manual/en/language.namespaces.fallback.php
too much php
+4  A: 

My impression is that namespaces are used in a cargo cult programming fashion. Because it's new, it gets used like crazy. Deeply nested namespaces, like in Doctrine2, add no further protection against name conflicts. And it's very obvious that \nested\name\spaces are just used to achieve a 1:1 mapping to directory/file names. Clearly a code smell.

But I suppose this phenomenon is also caused by trying to mimick Java module names in PHP. And furthermore the backslash syntax doesn't convey a sensible semantic as in other languages.

Anyway, the ability to rename classes while importing namespaces is a big bon. That's useful when it actually comes to mixing conflicting definitions. And the namespace syntax can simply be added, once an actual name conflict arises. (I see no need to implement namespaces right away, when name conflicts are that rare and for most projects a purely fictional problem.)
If you do it only when required, the awkward namespace syntax never even has to rear its ugly head. If there is only one namespace level to import, you can just use namespace1\Class as LocalName and don't convolute the application with any namespace1\Class syntax. (Still it's a better idea not to use overly generic class names in namespaces.)

mario
Thats about what I'm getting out of this. Like you said, I'm sure it can be useful once a conflict occurs - but so is renaming the conflicting class or thinking out you class structure correctly. Anyway, I thought I'd ask and see if I'm just missing something everyone else seems to see in namespaces...
Xeoncross
I would up vote you @mario, twice if I could. But I'm out of votes for today - great summary.
Alix Axel
+2  A: 

The point you seem to be missing is that namespace names are composable. I.e. you can do:

use Zend\Db\Table as Table;
$a = new Table\Rowset();
$b = new Table\Fields();

etc. I.e. it allows you to define your context (or set of contexts) and then refer to it. Of course, you can reduce it to just one name, but you don't have to. That btw also helps with generic class names - Fields may be too generic, but Table\Fields less to.

Another thing is if you get sick of Zend tables and want to write your own Db table classes, you change the above to:

use My\Own\Table as Table;

and all the code now uses your set of classes. Also, you don't actually define the class by the long name. What you do is:

namespace Zend\Db\Table;
class Rowset exteds AbstractRowset {
    function doStuff() {
       $this->fields = new Fields();
       if($this->fields->areBroken()) {
          throw Exception("Alas, fields are broken!");
       }
    }
 }

Note that here we have used 4 classes from Zend\Db\Table space, but never once had to refer to them by a long name. Of course, in real life it probably won't be as easy :), but the idea is that code - especially library code - tends to be localized - i.e. if you are in Db part of the library, chances are you are using DB-related classes much more than LDAP or PDF classes. Namespacing allows you to exploit this locality by using shorter names.

You are right that namespacing doesn't help with loading - since class should be still loaded using the full name. But once you've got your loader working, you can use nice aliases instead of ugly full names - just as in the filesystem you can use nice relative paths and symlinks instead of ugly full path.

StasM
1+ A well spoken beneficial use of aliases. I'm wondering what type of best-practice will occur once namespaces are in full use. (In the same way that MVC has lead to the standard of URI mapping to controller::method() names.)
Xeoncross