【问题标题】:Why "use" keyword in PHP needs to be used with Interface?为什么 PHP 中的“use”关键字需要与接口一起使用?
【发布时间】:2017-09-24 10:58:25
【问题描述】:

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

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

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

这里来自抽象工厂类。

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。我确实了解接口和继承的概念。我只是不知道为什么我们以这种方式包含接口。

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

What is the difference between an interface and abstract class?

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

我希望这些链接也对其他人有所帮助。

【问题讨论】:

    标签: php oop interface namespaces zend-framework2


    【解决方案1】:

    use 创建所用类的全限定名的本地别名。类名不仅仅是类的名称,它始终包含定义它的命名空间。

    如果你不使用use关键字来创建一个本地别名,php假设,该类在当前命名空间中(如果你没有在文件中声明命名空间,这是根命名空间@987654326 @)

    一个简单的例子

    // 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 是两个不同的类。


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

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

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

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

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

    【讨论】:

    • 所以你说的是命名空间是一种类型,它是你传递给函数的类型。我不明白的是你为什么将接口作为类型传递,为什么不将类作为类型传递。
    • 接口和类类型没有区别
    • @TomKoston 如果您有实现接口B 的类A,则使用接口作为函数参数,因为您可以将A 切换为其他东西(即模拟单元测试等..)。这使您可以更灵活地进行单元测试或扩展您的应用程序以应对未来的变化。您也可以使用 A 作为类型参数,但这是不必要的限制
    • 这是一个 SOLID 原则(依赖倒置)应该“依赖于抽象,而不是具体化 en.wikipedia.org/wiki/Dependency_inversion_principle
    • 谢谢~!这就解释了为什么人们将接口作为类型依赖项而不是具体类型作为依赖项传递。
    猜你喜欢
    • 2020-08-18
    • 2021-10-12
    • 1970-01-01
    • 2013-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    相关资源
    最近更新 更多