这是在PHP中使用命名空间的好方法吗?

12
我以前学过PHP中的命名空间使用,但最近看到一个项目使用了use关键字,然后访问带有命名空间的对象,就像它们是普通的没有命名空间一样。我的问题是,下面的代码是否正确,它有一个文件index.php并使用了命名空间MyLibrary\Base,然后使用use引入了\MyLibrary\Registry\MyLibrary\User\MyLibrary\Request。然后可以访问这些对象,而不需要在它们前面加上命名空间,在use部分以下的实际代码看起来像一个普通的PHP文件(没有命名空间)。
我想问这是否是使用命名空间的正确方式?还是我遗漏了什么?
文件:index.php
<?php
namespace MyLibrary\Base;

use \MyLibrary\Registry;
use \MyLibrary\User;
use \MyLibrary\Request;


class Base
{
    public $registry;

    function __construct($registry)
    {
        $this->registry = $registry;
        $this->user = New User;
        $this->request = new Request;
        # code...
    }
}
?>

文件:registry.class.php

<?php
namespace MyLibrary\Registry;

class Registry
{
    public $user;

    function __construct($user)
    {
        $this->user = $user;
        # code...
    }
}
?>
2个回答

7

是的。 use语句将类或命名空间名称导入当前作用域。为了让代码更简洁,PHP开发人员实现了命名空间的功能。

namespace MyFirstNamespace {
    class Foo {}
}
namespace MySecondNamespace {
    use \MyFirstNamespace\Foo as Bar;
    $foo = new Bar;
}

a) 使用命名空间可以使得代码更易读,因为命名空间通常比 Vendor_Package_Foo_Bar_XyzClass 更短; b) 你可以快速地使用不同的类来替换旧的类。

# use \MyFirstNamespace\Foo as Bar; // I don't like Foo anymore
use \MyFirstNamespace\SimilarToFoo as Bar;

1
这太棒了,让我现在就想使用命名空间,之前我真的不想用,因为我以为我会不得不在我的代码中处理那个看起来很邪恶的\\分隔符。这让我想起了Python,你必须导入库的方式。 - JasonDavis
实际上我应该说,这就像C#一样,他们使用... using System; using System.Collections.Generic;等等... 我只是没有意识到他们正在导入命名空间。我也可以看出用点/句号作为NS分隔符会更好看。 - JasonDavis
一个快速的问题,就像你发布的 use \MyFirstNamespace\Foo as Bar; 我知道你可以这样更改名称,但在我看到的代码中,他们像我的例子一样做了... use \MyFirstNamespace\Foo; 然后只需使用 Foo 访问,这是可能的吗?请注意,我没有将其设置为其他任何内容,或者您是否必须像这样设置它 use \MyFirstNamespace\Foo as Foo; - JasonDavis
使用 use \Foo\Bar\MyClassuse \Foo\Bar\MyClass as MyClass 是一样的。你完全可以选择是否设置别名。在大多数情况下,我也不会这样做 ;) - KingCrunch
完美,这正是我所希望听到的! - JasonDavis
如果你有时间的话,或许你可以协助解答这个问题。由于某些原因,这里的代码都无法正常工作:https://dev59.com/b2oy5IYBdhLWcg3wWss_ - JasonDavis

4

命名空间具有许多优点。

第一个优点是可以重复使用方法名称,甚至是类名称(如果存在于不同的命名空间中,并且有意义)。例如:

namespace \myNamespace\data\postgres;

class DataBase extends \PDO
{
}

namespace \myNamespace\data\mysql;

class DataBase extends \PDO
{
}

您甚至可以重复使用通常保留给PHP函数的名称。

namespace \myNamespace\dir;

function makedir ()
{
    if (// some condition is true)
    {
        \makedir ();
    }
}

所有这些都旨在使不同来源的代码更容易一起使用,而无需担心命名冲突。只要程序员足够谨慎地遵守一些简单的规则,那么命名冲突的可能性就会大大降低。实际上,为了避免命名冲突,你需要关注的唯一规则就是将你的命名空间的第一层设置为自己的。例如,使用你公司的名称或其他方式来标识你作为独特供应商的第一层命名空间,这样一切都会很好。
例如,我在我编写的所有代码中都使用\gordian作为根命名空间,因此我可以随意为该命名空间下的类命名,而不必担心与选择不同根命名空间的人发生冲突。
那么PEAR约定有什么问题呢?很多项目都遵循它们,包括流行的Zend框架。
答案是,名称变得非常笨重。例如,Zend遵循PEAR约定,使用一种伪命名空间。集合中的所有类都以Zend_开头,并且每个类层次结构级别都会添加一个进一步的部分到名称中。结果,你最终会得到类名如Zend_Db_Adaptor_Abstract和Zend_Dojo_Form_Decorator_TabContainer。
如果Zend更新其框架以使用命名空间(我被告知这正在发生于Zend Framework 2.0),那么它们将被替换为\Zend\Db\Adaptor\Abstract和\Zend\Dojo\Form\Decorator\TabContainer。那又怎样?答案是,你可以使用Use关键字将它们别名为更短的名称,就像你已经看到的那样。这意味着你不必一直写出完整的类名,而只需写出你已经别名的部分即可。
use \Zend\Dojo\Forn\Decorator as Dec;

$a = new Dec\TabContainer; // Not easy to do without namespaces!

此外,如果您已经在特定的命名空间中,那么您甚至不需要使用"use"关键字通过短名称访问同一命名空间中的其他项目,在这种情况下,它会自动为您处理。对于框架编写者来说,这是一个巨大的时间节省。
例如,在Zend Framework 2中,您可能会看到类似于下面的内容(由于我没有以任何方式参与其中,因此这只是一个示例,而不是来自实际ZF2源代码的内容)。
namespace \Zend\Db\Adaptor;

class Postgres extends Abstract // We don't need to use \Zend\Db\Adaptor\Abstract here because it's in the same namespace already anyway
{
}

还有其他的好处,例如使自动加载器变得非常简单(只要你的命名空间结构完全映射到文件系统目录结构)。

命名空间可能看起来像那些并不是非常重要,甚至似乎毫无意义的功能之一,但使用一段时间后,它们的用处将突然变得非常明显。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接