Home » Php » oop – PHP interface optional parameter

oop – PHP interface optional parameter

Posted by: admin July 12, 2020 Leave a comment

Questions:

I’m trying to make an generic interface for my service classes. I’m having trouble with a two class making use of the interface. They share a methode called create. The create methode excepts three parameters. I want it to make it so that the third parameter is optional so that both classes can work with it.

interface ServiceInterface{

    public static function create($var1, $var2, $thisOneIsOptional);

}

class ServiceObject1 implements ServiceInterface{

    public static function create($url, $server){
       //....
    }
 }

class ServiceObject2 implements ServiceInterface{

    public static function create($methode, $url, $id){
       //....
    }
}
How to&Answers:

It’s not the proper way to implement an interface.

First of all, an interface defines how a class should be used and an optional parameter could break this reason.

Besides that, even you have exactly two parameters, they should have its own meaning and this meaning should be shared.

There’s a huge difference between the interface method signature:

public static function create($var1, $var2);

and the two implemented methods:

public static function create($url, $server)

and:

public static function create($methode, $url)

Also, AFAIK, implementing this way will rise a strict standard violation because you’re changing the interface signature.

If you have to create a shared interface that has no meaning, there’s no reason to the interface be shared or even created.

Answer:

Classes implementing a method defined as an abstract signature on a parent class or by an interface must follow certain rules, but they do not have to match exactly.

This is not well documented, for example it’s not even mentioned in the PHP documentation of interfaces, but is touched upon by the documentation of abstract classes:

Furthermore the signatures of the methods must match, i.e. the type hints and the number of required arguments must be the same. For example, if the child class defines an optional argument, where the abstract method’s signature does not, there is no conflict in the signature.

In other words, the method must be capable of being called as per the signature, but it doesn’t rule out:

  1. Using different variable names in the implementation of the method
  2. Declaring additional optional arguments after the arguments declared in the method signature, if any

Taken from the question, this would work:

interface ServiceInterface{

    public static function create($var1, $var2);

}

class ServiceObject1 implements ServiceInterface{

    public static function create($url, $server){
       //....
    }
 }

class ServiceObject2 implements ServiceInterface{

    public static function create($methode, $url, $id = null){
       //....
    }
}

Answer:

In PHP 56+, you can use the ellipsis operator:

interface ServiceInterface {
    public static function create(...$params);
}

class ServiceObject1 implements ServiceInterface
{
    public static function create(...$params)
    {
        $url = $params[0];
        $server = $params[1];
        print "url = $url\n";
        print "server = $server\n";
    }
}

class ServiceObject2 implements ServiceInterface
{
    public static function create(...$params)
    {
        $method = $params[0];
        $url = $params[1];
        $id = $params[1];
        print "method = $method\n";
        print "url = $url\n";
        print "id = $id\n";
    }
}
print "ServiceObject1::create\n";
ServiceObject1::create("url", "server");
print "\nServiceObject2::create\n";
ServiceObject2::create("method", "url", "id");

Output:

ServiceObject1::create
url = url
server = server

ServiceObject2::create
method = method
url = url
id = url

/rant

To users complaining about what the OP want’s to do – While general advice is that this is bad idea to do, there exsist many cases in which the program really does not care what the parameters are in advance. An example of this would be if ther function was sumAll instead of create.

Answer:

You can do:

interface ServiceInterface{

    public static function create($url, $server, $id = null);

}

class ServiceObject1 implements ServiceInterface{

    public static function create($url, $server, $id = null){
       //....
    }
}

class ServiceObject2 implements ServiceInterface{

    public static function create($methode, $url, $id = null){
       //....
    }
}

But wouldn’t it be easier and more logical to make ServiceObject2 extend ServiceObject1, by doing this you can overwrite the function with an extra argument. And instead of requiring an object to be an instance of the interface, you require it to be an instance of ServiceObject1.