已在使用的 PHPUnit 中使用作曲家自动加载的致命错误



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

namespace User;
use UserContractsUserId;
use UserContractsUser as UserContract;
class User implements UserContract
{
    private $id;
    public function __construct(UserId $id)
    {
        $this->id = $id;
    }
    public function getId()
    {
        return $this->id;
    }
}
使用PHPUnit):

use UserContractsUserId;
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 UserContractsUserId as UserId because the name is already in use in /src/User/User.php on line 5

文件/文件夹结构:

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

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

  • PHP版本:5.6.13-1+deb.sury.org~ trusted +3
  • PHPUnit版本:5.0.3
  • OS: Ubuntu 14.04.3 LTS

我该如何解决这个问题?

不能将一个类导入到已经在命名空间中声明了相同别名的命名空间中。

已存在UserUserId,希望将UserContractsUserId导入User命名空间。这将使快捷键UserId产生歧义。

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

您可以在导入时使用别名,或者直接使用相对路径:

namespace User;
class User implements ContractsUser
{
    private $id;
    public function __construct(ContractsUserId $id) {}
}

更新2018-03-20:

有一个bug报告https://bugs.php.net/bug.php?id=66773,抱怨PHP在没有操作码缓存的情况下会触发这个错误,否则不会。原因是使用opcache时,编译是针对每个文件进行的,因此只考虑文件的内容是合理的期望。然而,错误似乎是先前加载文件中的现有类定义在导入"冲突"类时妨碍了。

它在PHP 7.0.13中以正确的方式修复了:每个单独的文件只说明它自己,如果您希望导入一个类并使用它的缩写名,您可以这样做,而不考虑名称空间中可能存在的任何其他类。您只是失去了对这些类的访问权限—这无关紧要,因为您的代码一开始就没有使用它们。如果你想改变它,你必须改变导入。

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

尝试如下:

use UserContractsUserId as UserIdContract;

可能你得到一个命名冲突因为你在做

use UserContractsUserId;

,但你也有UserIdUser类的同一命名空间。

所以…

namespace User;
use UserContractsUserId as UserIdContract;
use UserContractsUser as UserContract;
class User implements UserContract
{
    private $id;
    public function __construct(UserIdContract $id)
    {
        $this->id = $id;
    }
    public function getId()
    {
        return $this->id;
    }
}

希望有帮助!

相关内容

  • 没有找到相关文章

最新更新