I am a self-taught programmer and I am learning Zend Framework 2 at the moment.
I always wonder why every times when I'm trying to include a certain service, they are always required me to use Interface version of it.
For example, if I'm trying to use Service Locator, I will have to include serviceLocatorInterface in order to use Service Locator. Why can't I just use Service Locator class itself.
Here is from Abstract Factory class.
use Zend\ServiceManager\ServiceLocatorInterface;
Then I would use in it this way
public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
Here is another example from Zend tutorial, 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;
We include PostServiceInterface. Why not just PostService?
public function __construct(PostServiceInterface $postService)
We use the PostServiceInterface here. Why not just PostService as a Type.
I am sure this is a very simple answer that all students can answer but since i'm learning this myself so I am having a hard time understanding it.
PS. I do understand the concept of interface and inheritance. I just don't know why we include Interface this way.
Edit: After the answer I found a link that helps me understand better why people are passing interface as a type dependency instead of a concrete type.
What is the difference between an interface and abstract class?
http://kristopherwilson.com/2015/03/26/using-interfaces-effectively-in-php/
I hope those links help someone elses too.
use
creates an local alias of the used class's full qualified name. An class name isn't just the name of the class, it always contains the namespace, where it is defined.
If you don't use the use
keyword to create an local alias, php assumes, the class is in the current namespace (If you don't declare an namespace in the file, this is the root namespace \
)
A simple example
// 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
}
}
note, that \ClassName
and \Test\ClassName
are two different classes.
So why use PostServiceInterface
instead of PostService
You don't have to, but it's a good practice doing so with many benefits. I.e. you want to test the function later and don't have a PostService
. Creating an new class, which inherits from PostService
don't might be a good solution (and even couldn't be possible, because PostService could be declared final
)
They way out of this is: Don't use the class, use the interface as parameter. This principle is part of the SOLID principles, named Dependency Inversion Principle and states two things:
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.