有可能拥有一个包含私有/受保护方法的接口吗?

91

在PHP 5中,是否可以有一个具有私有/受保护方法的接口?

现在我的代码是:

interface iService
{
    private method1();
}

出现了错误:

解析错误:语法错误,意外的T_STRING,预期T_VARIABLE

我只是想确认一个接口只能包含公共方法。


2
我觉得这个答案令人失望。我希望接口也能支持受保护/私有方法。例如,我有一个类,在其中一个公共方法在抽象中实现,依赖于子类实现的受保护方法。我想使用接口来要求子类实现抽象公共方法所需的受保护方法。 - Stoutie
4
为此目的,请使用抽象基类。您可以结合两种方法:在接口中使用公共方法,在定义(并依赖于)抽象受保护方法的抽象基类中实现这些方法。 - Stijn de Witt
2
如果您可以声明私有或受保护的方法,那么它应该是 private function method1(); 而不是 private method1(); - tvanc
7个回答

146

PHP手册关于接口的页面明确说明:

在接口中声明的所有方法必须是公共的;这就是接口的本质。

我想这解释了你所遇到的错误 ;-)


23

接口用于描述实现该接口的类的公共方法。您不能在接口中有私有方法。接口中的任何方法都被认为是正在使用的,不应更改。

这里是PHP中的接口文档链接,但这在面向对象编程中是标准做法。


4
在其他编程语言中,比如Java,你可以在接口中使用访问修饰符。 - User123456

13

通常情况下,接口只能有公共成员,因为接口的唯一功能是被继承。

来自PHPfreaks.com教程:

PHP5具有接口特性。不要与更一般意义上的接口混淆,接口关键字创建的实体可用于在不必像抽象类那样扩展它们的情况下对类强制执行共同的接口。而是实现接口。

接口与抽象类不同。首先,它们实际上不是类。它们不定义属性,也不定义任何行为。在接口中声明的方法必须在实现它的类中声明。

由于在更一般意义上,一个接口是对象与其他代码交互的定义,所以所有方法必须声明为公共的(请参见本章节中关于可见性的部分)。使用抽象类时,抽象方法可以有任何可见性,但扩展类必须使用相同(或更弱)的可见性来实现其实现。实现接口将把这些方法作为抽象方法添加到主题类中,未实现它将导致类似以下内容的错误:

致命错误:SomeConcreteClass类包含n个抽象方法,并且因此必须声明为抽象或实现剩余的方法。是的,抽象类可以实现接口。


5
很遗憾,因为我希望在抽象类中实现一个公共方法以满足接口要求,并依赖于由接口强制执行的受保护方法。这样,抽象类可以提供公共接口,但由子类来实现底层逻辑。明白吗? - Stoutie
4
似乎你希望子类实现的方法是抽象的,这样任何子类必须实现它。但这与接口无关。 - Sven
@Stoutie 接口不应该为抽象类的实现定义支持方法 - 应该通过在抽象类上定义一个抽象方法来完成。 - jave.web

6

接口是类型声明。一个类型是一组值,加上一组可以从外部执行的操作。私有方法不符合这个概念。

interface T {
  public /*int*/ function f(array $a);
}
interface U {
  public /*T*/ function g(T $t);
}

class C implements U {
    public function g(T $t) {
        ...
        $x = $t->f();
        ...
    }
}

接口很有用,因为它们定义了对象的接口,即对象如何与其环境交互。

现在假设T::f可以声明为私有。那么它对其他对象有什么用处呢?它不能从外部调用,也不是其接口的一部分。


同意... 但它可以被保护起来,对吧? 因为抽象类允许... - asdfasdfasdf

4

在许多情况下,接口定义可以帮助其他模块保证类的行为和API。在这些情况下,私有方法并不是其他模块可以访问或理解的内容。这就是为什么您永远不能将私有方法放在接口上的原因。


2
如上所述,接口只能定义公开可见的方法。我想展示一个如何处理受保护方法的例子。为了强制使用特定的受保护方法,可以创建一个实现接口的抽象类。
如果抽象类已经能够处理部分工作以简化实际实现,则这尤其有意义。例如,这里的抽象类负责实例化结果对象,这是始终需要的:
首先,是接口。
interface iService
{
   /**
    * The method expects an instance of ServiceResult to be returned.
    * @return ServiceResult
    */
    public function doSomething();
}

抽象类定义内部方法的结构:
abstract class AbstractService implements iService
{
    public function doSomething()
    {
        // prepare the result instance, so extending classes
        // do not have to do it manually themselves.
        $result = new ServiceResult();

        $this->process($result);

        return $result;
    }

   /**
    * Force all classes that extend this to implement
    * this method.
    *
    * @param ServiceResult $result
    */
    abstract protected function process($result);
}

实际实现的类会自动继承抽象类的接口,只需要实现受保护方法即可。
class ExampleService extends AbstractService
{
    protected function process($result)
    {
         $result->setSuccess('All done');
    }
}

通过这种方式,接口可以满足公共契约,并且通过AbstractService类,实现内部契约。应用程序只需要在适用的地方强制使用AbstractService类即可。


1

大错特错,接口中的任何方法都不可能有私有或受保护的访问标识符。

**在接口中声明的所有方法都必须是公共的;这是接口的本质。

关于接口的其他有趣事实

接口可以使用 extends 运算符像类一样进行扩展。它们只能扩展其他接口。(来源:https://www.php.net/manual/en/language.oop5.interfaces.php)

请注意,在接口中声明构造函数是可能的,在某些情况下非常有用,例如供工厂使用。签名应该与子类中的相同。

在您的情况下,甚至还存在另一个问题-函数声明中缺少 function 关键字。 它应该是

interface iService
{
    public function method1();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接