1

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.

mega6382
  • 9,211
  • 17
  • 48
  • 69
Tom Koston
  • 35
  • 5

1 Answers1

1

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.

Philipp
  • 15,377
  • 4
  • 35
  • 52
  • So what you are saying is namespace is a type and it's a type that you pass to the function. What I don't understand is why are you passing Interface as a type and why don't you pass a Class as a type. – Tom Koston Apr 26 '17 at 21:30
  • There's no difference between interface and class type – Philipp Apr 26 '17 at 21:33
  • @TomKoston If you have class `A` which implements interface `B`, you use the interface as function param, because you could switch `A` with something else (i.e mock for unit testing, etc..). That gives you more flexibility for unit testing or extending your application for future changes. You could also have used `A` as type param, but this is an unnecessary restriction – Philipp Apr 26 '17 at 21:39
  • This is a SOLID principle (dependency inversion) *one should “depend upon abstractions, [not] concretions* https://en.wikipedia.org/wiki/Dependency_inversion_principle – Philipp Apr 26 '17 at 21:44
  • Thank you~! that explains why people are passing interface as a type dependency instead of concrete type as a dependency. – Tom Koston Apr 26 '17 at 21:51