Are namespaces really all that useful in frameworks?
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_U开发者_运维知识库ser;
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.
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.)
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
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.
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.
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.
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.
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?
精彩评论