名称空间在框架中真的有用吗?

时间:2010-06-30 21:40:17

标签: php namespaces class

据我所知,我们在PHP中使用命名空间的唯一原因是修复了类(+函数和常量)与其他同名类冲突的问题。

问题是大多数框架都设置了自动加载文件系统层次结构来反映类的名称。并且没有人实际上需要()s或include()s文件。

那么命名空间如何帮助它呢?要么根据它的名称加载类:

new Zend_Db_Table_Rowset_Abstract;

或关闭它的命名空间

new Zend\Db\Table\Rowset\Abstract;

无论哪种方式,我都只能用这个名字创建一个类。

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

更新 我不确定我是否明白了这一点。

即使我在其中创建了两个具有相同class Zend\Db\Table\Rowset\Abstract的文件,我仍然无法将它们一起使用,因为它们都声称具有相同的命名空间。我必须改变他们的命名空间名称,这是我们已经做的!

这让我相信命名空间的唯一用途是函数名称。现在我们终于可以将三个函数命名为同一个东西!

或者等等,我忘了你不能这样做因为每个都需要命名空间前缀!

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

以ircmaxell为例:

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

这有什么不同而不是没有?

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

这也是一个整洁的声音功能 - 但它真正为我们做了什么?

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

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

现在您不能拥有名为“UserModel”的类,因为您有该术语的命名空间设置。您还仍然不能在同一别名下命名两个类。

我想好的是你可以重命名长Zend_Db_Table_Rowset_Abstract

use Zend_Db_Table_Rowset_Abstract as RowAbstract;

导致开发人员对系统中定义和来自不存在的类“RowAbstract”的位置感到困惑。

7 个答案:

答案 0 :(得分:13)

实际上,您可以创建多个具有相同名称的类

假设您有两个类:

\Application\Controller\User

\Application\Model\User

如果没有别名,您无法将两者都导入到同一个文件中,但您仍然可以使用相同的方式定义:

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

另外,您可以导入和别名:

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

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

所以它确实非常强大,因为它确实允许你按照你想要的方式命名你的类(并在代码中用任意名称引用它们)。唯一的规则是保留关键字...请参阅:http://www.php.net/manual/en/language.namespaces.importing.php

答案 1 :(得分:13)

我的印象是命名空间以cargo cult programming方式使用。因为它是新的,它会被疯狂地使用。深层嵌套的命名空间(如Doctrine2中)不会对名称冲突进行进一步的保护。很明显,\ nested \ name \ spaces只是用于实现目录/文件名的1:1映射。显然代码味道。

但我认为这种现象也是由于试图在PHP中模仿Java模块名称引起的。此外,反斜杠语法不像其他语言那样传达合理的语义。

无论如何,在导入名称空间时重命名类的能力是一个很大的问题。当实际上混合冲突的定义时,这很有用。一旦出现实际名称冲突,就可以简单地添加命名空间语法。 (我认为没有必要立即实现命名空间,因为名称冲突很少见,大多数项目都是纯粹的虚构问题。)
如果你只在需要的时候才这样做,那么笨拙的命名空间语法甚至不必重复它的丑陋头脑。如果只导入一个名称空间级别,则只能use namespace1\Class as LocalName并且不会使用任何namespace1\Class语法卷积应用程序。 (最好不要在名称空间中使用过于通用的类名。)

答案 2 :(得分:7)

您似乎缺少的是命名空间名称是可组合的。即你可以这样做:

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

等。即它允许您定义上下文(或上下文集),然后引用它。当然,您可以将其缩减为一个名称,但您不必这样做。 btw也有助于泛型类名称 - 字段可能过于通用,但Table \ Fields少于。

另一件事是,如果您厌倦了Zend表并希望编写自己的Db表类,则将上述内容更改为:

use My\Own\Table as Table;

现在所有代码都使用了您的一组类。 此外,您实际上并不是通过长名称来定义类。你做的是:

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

请注意,这里我们使用了Zend \ Db \ Table空间中的4个类,但从来没有用过长名称来引用它们。当然,在现实生活中它可能不会那么简单:),但是这个想法是代码 - 特别是库代码 - 倾向于本地化 - 即如果你在Db部分库中,很可能你正在使用DB相关类比LDAP或PDF类更多。命名空间允许您使用较短的名称来利用此位置。

你是对的,命名空间对加载没有帮助 - 因为类仍然应该使用全名加载。但是一旦你的加载器工作,你可以使用漂亮的别名而不是丑陋的全名 - 就像在文件系统中你可以使用漂亮的相对路径和符号链接而不是丑陋的完整路径。

答案 3 :(得分:3)

在您的示例 Zend 框架中,您可以将namespace Zend;放在每个类文件的顶部,从所有类和函数中删除Zend_前缀,然后(大多数情况下)不需要再次担心名称冲突。您的Zend_Date类可以重命名为Date,而不会干扰内置日期类。同时,您的框架用户可以编写Zend\Date而不是Zend_Date,而不再需要输入{{1}},但他们现在还有其他几种选项可以更轻松地访问该类。

答案 4 :(得分:2)

除非你有一个包含多个开发人员的大项目,否则使用命名空间可能不值得。我甚至认为命名空间被高估了。

例如,在Java中(因为很少有人在PHP中使用命名空间,我找不到任何类似的例子)。这些是我的IDE(Eclipse)中List的选择:

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

在这种情况下,我真的不明白为什么他们不能仅将java.util.List保留为唯一的List,例如将java.awt.List重命名为ScrollingList ,它实际上描述了它是什么,使它更明显,它是一个GUI元素,并避免碰撞。我宁愿输入一个更长,更具描述性的类名,而不是处理它。

至于上述海报之一,如果你团队中的每个人都在制作一个名为Database的课程,或许你需要进行一些设计讨论并只使用一个Database课程,而不是推动每个人的个人复制到命名空间。

答案 5 :(得分:1)

您是否真的想创建一个名为 Zend_Db_Table_Rowset_Abstract 的新类?

更可能的情况是,您有一个名为Date,Project,User或类似东西的本地类,或者您有一个已经拥有这些类的框架。通过拥有名称空间,不应该有任何冲突。

在web2project中,我们刚刚在v2.0中添加了命名空间支持(但我们不需要PHP 5.3),因为我们的类(如Date,DBQuery,Mail和其他一些类)很容易与事物发生冲突。虽然我们没有打算在系统中添加外部框架,但如果他们想要的话,其他人可以很容易。

是否有更简洁的方法来解决问题?潜在的......但是这在Java世界里有着成堆的库,所以它并不是全新的空间。

答案 6 :(得分:1)

也许如果你稍微扩大你的观点:)

“据我所知,我们在PHP中使用命名空间的唯一原因是修复类(+函数和常量)与其他同名类冲突的问题。” - 是的,这是一个巨大的问题,多年来在每个没有命名空间的语言中都会引起问题 - 每个人都会创建一个类数据库,日期,URL等,这样就修复了它:)

“问题是大多数框架都设置了自动加载和文件系统层次结构来反映类的名称。而且实际上没有人需要()s或include()s文件。” - 实际上,他们通常只是因为一些常见的框架必须提出解决缺乏命名空间的实践,并不意味着那些工作或黑客攻击应该无效地解决问题的“真正”解决方案。全部:))

遵循?