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

Xeo*_*oss 12 php namespaces class

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

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

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

new Zend_Db_Table_Rowset_Abstract;
Run Code Online (Sandbox Code Playgroud)

或者它的命名空间

new Zend\Db\Table\Rowset\Abstract;
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,我只是能够创建一个具有此名称的类.

/var/www/public/Zend/Db/Table/Rowset/Abstract.php
Run Code Online (Sandbox Code Playgroud)

更新 我不确定我是否明白了.

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

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

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

a\myfunction();
b\myfunction();
c\myfunction();
Run Code Online (Sandbox Code Playgroud)

以ircmaxell为例:

$model = new \Application\Model\User;
$controller = new \Application\Controller\User;
Run Code Online (Sandbox Code Playgroud)

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

$model = new Application_Model_User;
$controller = new Application_Controller_User;
Run Code Online (Sandbox Code Playgroud)

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

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

$foo = new UserModel;
$bar = new UserController;
Run Code Online (Sandbox Code Playgroud)

现在您不能拥有一个名为"UserModel"的类,因为您有该术语的命名空间设置.您也仍然不能有相同的别名下名为两班.

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

use Zend_Db_Table_Rowset_Abstract as RowAbstract;
Run Code Online (Sandbox Code Playgroud)

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

irc*_*ell 13

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

假设你有2个类:

\Application\Controller\User
Run Code Online (Sandbox Code Playgroud)

\Application\Model\User
Run Code Online (Sandbox Code Playgroud)

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

$model = new \Application\Model\User;
$controller = new \Application\Controller\User;
Run Code Online (Sandbox Code Playgroud)

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

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

$foo = new UserModel;
$bar = new UserController;
Run Code Online (Sandbox Code Playgroud)

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

  • 我快门想一想这对一些项目的应用范围有什么影响.一些新程序员将在整个项目中留下名称空间别名,因为他不想输入全名.的xD (3认同)
  • @Xeoncross:实际上使用别名是一个好主意,因为它使代码更短,更容易阅读,允许您提供描述性名称,并允许您通过替换要交换的类的****来交换类.在具有别名的语言中,这一直是这样做的,坦率地说,这是一个有用的功能.实际上花时间阅读文件的标题并不是很麻烦,在这种情况下进行这样的声明.它肯定比通过include语句导入的全局常量或函数更不混乱. (2认同)

mar*_*rio 13

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

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

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


Sta*_*asM 7

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

use Zend\Db\Table as Table;
$a = new Table\Rowset();
$b = new Table\Fields();
Run Code Online (Sandbox Code Playgroud)

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

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

use My\Own\Table as Table;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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