PHP接口可选参数

时间:2017-05-18 11:23:34

标签: php oop interface

我试图为我的服务类创建一个通用接口。我在使用界面的两个班级时遇到了麻烦。他们共享一个名为create的方法。 create method除了三个参数。我希望它能够使第三个参数是可选的,这样两个类都可以使用它。

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){
       //....
    }
}

4 个答案:

答案 0 :(得分:8)

这不是实现接口的正确方法。

首先,接口定义了如何使用类,可选参数可能会破坏这个原因。

除此之外,即使你有两个参数,它们也应该有自己的含义,这个意思应该是共享的。

接口方法签名之间存在巨大差异:

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

和两个实现的方法:

public static function create($url, $server)

public static function create($methode, $url)

此外,实施这种方式的AFAIK会引起严格的标准违规,因为您正在更改界面签名。

如果您必须创建一个没有意义的共享界面,则没有理由共享或甚至创建界面。

答案 1 :(得分:4)

实现在父类或接口上定义为抽象签名的方法的类必须遵循某些规则,但它们不必完全匹配。

这个没有详细记录,例如PHP documentation of interfaces中甚至没有提到它,但是documentation of abstract classes触及了它:

  

此外,方法的签名必须匹配,即类型提示和所需参数的数量必须相同。例如,如果子类定义了一个可选参数,而抽象方法的签名没有,则签名中没有冲突。

换句话说,该方法必须能够根据签名进行调用,但不排除:

  1. 在方法实施中使用不同的变量名称
  2. 在方法签名中声明的参数后声明其他可选参数,如果有的话
  3. 从问题中得知,这可行:

    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){
           //....
        }
    }
    

答案 2 :(得分:1)

在PHP 56+中,您可以使用省略号运算符:

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");

输出:

ServiceObject1::create
url = url
server = server

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

/ rant

对于抱怨OP想要做什么的用户-尽管一般的建议是这样做不是一个好主意,但在许多情况下,程序实际上并不关心预先设置的参数。例如,如果该函数是sumAll而不是create

答案 3 :(得分:0)

你可以这样做:

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){
       //....
    }
}

但是,使ServiceObject2扩展ServiceObject1变得更容易也更合理,通过这样做,您可以使用额外的参数覆盖该函数。而不是要求对象成为接口的实例,而是要求它是ServiceObject1的实例。