为什么PHP中的"use"关键字需要和Interface一起使用?

Why "use" keyword in PHP needs to be used with Interface?

我是一名自学成才的程序员,目前正在学习 Zend Framework 2。

我总是想知道为什么每次我尝试包含某个服务时,他们总是要求我使用它的接口版本。

例如,如果我尝试使用服务定位器,则必须包含 serviceLocatorInterface 才能使用服务定位器。 为什么我不能只使用服务定位器 class 本身。

这里来自抽象工厂class。

use Zend\ServiceManager\ServiceLocatorInterface;

那我就这样用

public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)

这是 Zend 教程中的另一个示例,https://framework.zend.com/manual/2.4/en/in-depth-guide/services-and-servicemanager.html#bringing-the-service-into-the-controller

use Blog\Service\PostServiceInterface;

我们包括 PostServiceInterface。为什么不只是 PostService?

public function __construct(PostServiceInterface $postService)

我们在这里使用PostServiceInterface。为什么不将 PostService 作为类型。

我相信这是一个所有学生都能回答的非常简单的答案,但由于我是自己学习的,所以我很难理解它。

PS。我确实了解接口和继承的概念。我只是不知道为什么我们要这样包含接口。

编辑:回答后我发现了一个 link 可以帮助我更好地理解为什么人们将接口作为类型依赖项而不是具体类型传递。

What is the difference between an interface and abstract class?

http://kristopherwilson.com/2015/03/26/using-interfaces-effectively-in-php/

我希望那些 link 也能帮助其他人。

use 为使用过的 class 的 全限定名 创建一个本地别名。 class 名称不仅仅是 class 的名称,它始终包含定义它的命名空间。

如果您不使用 use 关键字创建本地别名,php 假定 class 在当前命名空间中(如果您不声明文件中的命名空间,这是根命名空间 \)

一个简单的例子

// the current namespace
namespace Foo;

use Test\ClassName;

class Bar {
    public function __construct(Baz $a) {
        // Baz isn't a full qualified class name (missing leading \), so
        // php assumes, Baz is inside the current namespace Foo
        // => full class name is \Foo\Baz;
    }

    public function doSomething(ClassName $a) {
        // ClassName isn't a full qualified class name, BUT there is an use
        // statement, which imported ClassName to the local file
        // => \Test\ClassName
    }

    public function doSomethingElse(\ClassName $a) {
        // ClassName IS a full qualifed class name
        // => \ClassName
    }
}

请注意,\ClassName\Test\ClassName 是两个不同的 class。


那么为什么要用PostServiceInterface而不是PostService

您不必这样做,但这样做有很多好处,是一种很好的做法。 IE。您想稍后测试该功能并且没有 PostService。创建一个继承自 PostService 的新 class 可能不是一个好的解决方案(甚至不可能,因为可以声明 PostService final

他们的出路是:不要使用 class,使用接口作为参数。该原则是 SOLID principles, named Dependency Inversion Principle 的一部分,并说明两件事:

  • 高层模块不应该依赖低层模块。两者都应该依赖于抽象。

  • 抽象不应该依赖于细节。细节应该取决于抽象。