我是一名自学成才的程序员,目前我正在学习Zend Framework 2.
我总是想知道为什么每次当我试图包含某项服务时,他们总是要求我使用它的界面版本。
例如,如果我尝试使用服务定位器,我将必须包含 serviceLocatorInterface 才能使用服务定位器。 为什么我不能只使用Service Locator类本身。
这是来自Abstract Factory类。
use Zend\ServiceManager\ServiceLocatorInterface;
然后我会以这种方式使用
public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
中的另一个示例
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/
我希望这些链接也可以帮助别人。
答案 0 :(得分:1)
use
创建已使用类完全限定名称的本地别名。类名不仅仅是类的名称,它始终包含定义它的名称空间。
如果你不使用use
关键字创建一个本地别名,那么php假定,该类在当前命名空间中(如果你不在文件中声明一个命名空间,这个是根名称空间\
)
一个简单的例子
// 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
你不必这样做,但这样做有很多好处。即您想稍后测试该功能并且没有PostService
。创建一个继承自PostService
的新类可能是一个很好的解决方案(甚至无法实现,因为可以声明PostService final
)
他们的出路是:不要使用该类,使用接口作为参数。这个原则是SOLID原则的一部分,名为 Dependency Inversion Principle ,并说明了两件事:
高级模块不应依赖于低级模块。两者都应该取决于抽象。
抽象不应该依赖于细节。细节应取决于抽象。