Search code examples
phpoopinterfacenamespaceszend-framework2

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


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.


Solution

  • 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.