在 PHPUnit 中使用 composer 的自动加载时出现名称已在使用中的致命错误

Name already in use fatal error using composer's autoload in PHPUnit

使用 PSR-4 自动加载和 Composer,当我尝试测试这个 class:

namespace User;

use User\Contracts\UserId;
use User\Contracts\User as UserContract;

class User implements UserContract
{
    private $id;

    public function __construct(UserId $id)
    {
        $this->id = $id;
    }

    public function getId()
    {
        return $this->id;
    }
}

使用PHP单位:

use User\Contracts\UserId;

class UserTest extends \PHPUnit_Framework_TestCase
{
    public function test_the_identifier_can_be_used_as_string()
    {
        $identifier = m::mock(UserId::class);
        $identifier->shouldReceive('__toString')->once()->andReturn('foo');

        $user = new User($identifier);

        $this->assertSame('foo', (string) $user->getId());
    }
}

我在控制台收到这个错误

PHP Fatal error:  Cannot use User\Contracts\UserId as UserId because the name is already in use in /src/User/User.php on line 5

这是 file/folder 结构:

src
`-- User
    |-- Contracts
    |    |-- User.php
    |    `-- UserId.php
    |-- User.php
    `-- UserId.php
tests
`-- User
    |-- UserIdTest.php
    `-- UserTest.php

我已经对这个问题做了很多搜索,但我还没有找到任何解决方案。

我该如何解决这个问题?

尝试以下操作:

use User\Contracts\UserId as UserIdContract;

可能您遇到了命名冲突,因为您正在做

use User\Contracts\UserId;

但您在 User class.

的同一命名空间中也有 UserId

所以...

namespace User;

use User\Contracts\UserId as UserIdContract;
use User\Contracts\User as UserContract;

class User implements UserContract
{
    private $id;

    public function __construct(UserIdContract $id)
    {
        $this->id = $id;
    }

    public function getId()
    {
        return $this->id;
    }
}

希望对您有所帮助!

您不能将 class 导入到已经在其中声明了相同别名的命名空间。

您有 \User\UserId 并且想要将 \User\Contracts\UserId 导入 \User 命名空间。这会使快捷方式 UserId 不明确。

http://php.net/manual/en/language.namespaces.importing.php#117334

导入时可以使用别名,也可以直接使用相对路径:

namespace User;

class User implements Contracts\User
{
    private $id;

    public function __construct(Contracts\UserId $id) {}
}

2018-03-20更新:

有一个错误报告 https://bugs.php.net/bug.php?id=66773 抱怨 PHP 如果在没有操作码缓存的情况下使用会触发此错误,否则不会。原因是使用 opcache 编译是按文件完成的,并且只考虑文件的内容是合理的期望。但是,错误似乎是导入 "conflicting" classes.

时,先前加载文件中的现有 class 定义受阻

它已在 PHP 7.0.13 中以正确的方式修复:每个文件只占其自身,如果您希望导入 class 并按 [=41] 使用它=] 名称,您可以这样做,而不管命名空间中可能存在的任何其他 classes。您只是失去了对这些 classes 的访问权——这无关紧要,因为您的代码一开始就没有使用它们。如果您想要更改,则必须更改导入。

由于 opcache 通常在命令行上被禁用,因此您在使用 PHPUnit 时很可能会触发此错误。