请说明什么时候应该使用PHP interface,什么时候应该使用abstract class

如何将abstract class更改为interface

#1 楼

如果要强制开发人员(包括您自己)在系统中工作,请在他们要构建的类上实现一定数量的方法。

要强制使用抽象类开发人员在系统(包括您自己)中工作以实现一定数量的方法,并且您想提供一些基本方法来帮助他们开发子类。

要记住的另一件事是,客户端类只能扩展一个抽象类,而它们可以实现多个接口。因此,如果要在抽象类中定义行为契约,则意味着每个子类只能遵循一个契约。有时候,当您想迫使用户程序员沿着特定的路径前进时,这是一件好事。有时候这会很糟糕。想象一下,如果PHP的Countable和Iterator接口是抽象类而不是接口。

当不确定哪种方法(如下面的cletus所述)时,一种常见的方法是创建一个接口,然后让您的抽象类实现该接口。

评论


我整天都在努力了解抽象和接口类的用法,您的帖子对此一目了然。非常感谢艾伦

– afarazit
2011年5月21日在12:51

抽象类的另一个优点是可以定义受保护的抽象方法。并非总是有用,但在某些体系结构中可以派上用场。

– netcoder
2011年6月16日14:18



所以在很多情况下,由于灵活性,我们应该使用抽象类-这是我的结论:)

–ymakux
14年2月14日在11:48

@volocuga:不一定像艾伦指出的那样,只能扩展一个摘要。我个人不喜欢抽象实现接口的想法,因为它会导致代码混淆,并且不太直接,IMO。

– T_Conroy
14-10-29在15:23

#2 楼

Abstract ClassInterface之间的区别:

抽象类

抽象类可以提供某些功能,而其余的则留给派生类。


派生类可能会覆盖也可能不会覆盖基类中定义的具体功能。
从抽象类扩展的子类在逻辑上应该相关。

接口

接口不能包含任何功能。它只包含方法的定义。


派生类必须为接口中定义的所有方法提供代码。
完全不同且不相关的类可以在逻辑上分组一起使用界面。


评论


您可以提供一个真实的例子来演示它吗?

– RN库什瓦哈
2015年4月30日在11:02



抽象类X实现Y和X类实现Y有什么区别?

– Webinan
15年7月9日在20:26

@Webinan在抽象类X实现Y中,您声明X的批量功能应在派生类中实现,并且抽象类和派生类都必须包含在Y中定义的函数,而类X实现Y仅意味着类X必须包含如果您的接口Y不打算由XI以外的任何其他类实现,则实际上会跳过将Y定义为接口,而仅将Y中的功能实现为公共/受保护/私有抽象功能,以确保实现了它们。在派生阶级中。

– CalleBergström
16-2-22在13:47



接口不仅可以包含方法的定义,还可以包含常量

–热烈
18/09/20在13:54

喜欢您的比较。因此想添加一些东西。接口可以具有开箱即用的类常量,而抽象类则不能。

–诺曼·易卜拉欣
18/12/4在10:29



#3 楼

为什么要使用抽象类?以下是一个简单的示例。假设我们有以下代码:

<?php 

class Fruit {
    private $color;

    public function eat() {
        // chew
    }

    public function setColor($c) {
        $this->color = $c;
    }
}

class Apple extends Fruit {
    public function eat() {
        // chew until core
    }
}

class Orange extends Fruit {
    public function eat() {
        // peeling
        // chew
    }
}


现在我给你一个苹果,你就可以吃了。
它的味道如何?它尝起来像苹果。

<?php 
$apple = new Apple();
$apple->eat();

// Now I give you a fruit.
$fruit = new Fruit();
$fruit->eat();


那是什么样的味道?好吧,这没有多大意义,所以您不应该这样做。这是通过使Fruit类及其内部的eat方法成为抽象来实现的。

<?php 
abstract class Fruit {
    private $color;

    abstract public function eat(){}

    public function setColor($c) {
        $this->color = $c;
    }
}
?>


抽象类就像一个接口,但是您可以定义方法在抽象类中,而在接口中,它们都是抽象的。抽象类可以同时具有空方法和工作/具体方法。在接口中,在那里定义的函数不能有主体。在抽象类中,它们可以。

一个真实的示例:

<?php 
abstract class person {

    public $LastName;
    public $FirstName;
    public $BirthDate;

    abstract protected function write_info();
}

final class employee extends person{

    public $EmployeeNumber;
    public $DateHired;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to emloyee dbase table <br>";   
    }
}

final class student extends person{

    public $StudentNumber;
    public $CourseName;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to student dbase table <br>";
    }
}

///----------
$personA = new employee;
$personB = new student;

$personA->FirstName="Joe";
$personA->LastName="Sbody";

$personB->FirstName="Ben";
$personB->LastName="Dover";

$personA->write_info();
// Writing Sbody's info to emloyee dbase table
$personB->write_info();
// Writing Dover's info to student dbase table 


评论


嗨,这个答案可能由于其格式化方式而被否决了。如果它不是一个大的代码块(将四个空格放入一个代码块中,将文本缩进以将其从该块中取出),并且从某个地方复制粘贴(看起来像这样),那将是很好的礼貌地归功于他们。

–卡米洛·马丁(Camilo Martin)
13年4月18日在18:28

我爱你,以水果为榜样!自从我开始学习php以来,这个例子让我很清楚,非常感谢

– Raheel
2014-09-26 14:55

+1味道如何?好吧,这没有多大意义,所以您不应该这样做。现在我知道抽象了!

– Webinan
15年7月9日在20:31

最终关键字有什么作用?很棒的帖子,谢谢。

– Gus
16年11月4日在17:49

@VineeshKalarickal在Person示例中,我所不了解的是:1)使用抽象类Person(如示例中); 2)将Person编写为标准类,并使Employee和Student覆盖write_info()方法。

–联邦快递
16-12-12在21:21



#4 楼

最佳实践是使用接口来指定合同和抽象类,这只是其一种实现。该抽象类可以填充很多样板文件,因此您可以通过覆盖需要或想要的内容来创建实现,而不必强迫您使用特定的实现。

#5 楼

只是将其混为一谈,但是正如Cletus提到的将接口与抽象类结合使用时,我经常使用该接口来阐明我的设计思想。

例如:

<?php
class parser implements parserDecoratorPattern {
    //...
}


这样,任何阅读我的代码的人(并且知道装饰器模式是什么)都将立即知道a)我如何构建解析器和b)能够看到使用了什么方法来实现装饰器模式。

而且,我可能不是Java / C ++ / etc程序员,但是在这里数据类型可以发挥作用。您的对象属于一种类型,当您将它们传递给类型时,将以编程方式起作用。将可收缩项移入接口仅指示方法返回的类型,而不指示实现该方法的类的基类型。

,这太迟了,我想不出更好的伪代码例如,但这里是:

<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)


评论


多么棒的例子! ;)

–乔尔·墨菲(Joel Murphy)
13年5月30日在0:21

@ matt2000现在不性别歧视,并且也适用于同性婚姻。很棒的编辑。 :)

–奥斯汀·豪根
2014年12月5日在6:23

这是一个了不起的例子!但是,我认为您不能实例化一个抽象类,而是可以实例化一个从抽象类扩展的类。

– Arrielle Nguyen
15年2月26日在9:41

不会使sudo代码至少看起来像所讨论的语言。有人应该在里面放一些美元。

–我曾经摔过一只熊。
2015年4月9日在16:07

尽管该示例很有趣,但我们无法直接实例化一个抽象类,请对示例进行更改,以使人们可能不会将其视为PHP中的有效用法。

–saji89
2015年12月9日在8:32

#6 楼

主要区别是抽象类可以包含默认实现,而接口不能包含默认实现。

接口是行为契约,没有任何实现。

#7 楼

另外,只想在这里补充一点,仅仅是因为其他任何OO语言都具有某种接口和抽象,也不意味着它们具有与PHP相同的含义和目的。抽象/接口的使用略有不同,而PHP中的接口实际上没有真正的功能。它们仅出于语义和与方案相关的原因而使用。关键是要有一个尽可能灵活,可扩展且对将来的扩展安全的项目,无论以后的开发人员是否有完全不同的使用计划。

如果您的英语不是母语,您可能会查找“抽象和接口”实际上是什么。并寻找同义词。

这可能会比喻为您提供帮助:

INTERFACE

比方说,您烤了一种新蛋糕草莓,你编了一个食谱,描述了成分和步骤。
只有您知道为什么品尝得这么好,您的客人喜欢它。
然后您决定发布食谱,以便其他人也可以尝试该蛋糕。

这里的重点是


-正确处理
-注意
-防止可能变质的东西(如草莓或其他过多的东西)
-使尝试的人容易使用
-告诉您要执行多长时间(例如搅拌)
-告诉您可以执行哪些操作而不必执行


正是这样描述了接口。它是一个指南,是一组遵循食谱内容的说明。
就像您将用PHP创建一个项目,并且想要在GitHub上或与您的同伴或其他任何人一起提供代码一样。
界面是人们可以做什么,而你不应该做什么。持有它的规则-如果您不遵守,则会破坏整个构造。



ABSTRACTION

在这里继续这个比喻...想象一下,您这次是客人,正在吃那个蛋糕。然后,您现在就可以使用食谱尝试做蛋糕了。
但是您想要添加新成分或更改/跳过食谱中描述的步骤。那么接下来呢?计划该蛋糕的其他版本。
这一次是黑浆果而不是草莓果子,还有更多的香草奶油...好吃。

这就是您可以考虑扩展的原始蛋糕。基本上,您可以通过创建新食谱来对其进行抽象,因为它与众不同。它具有一些新步骤和其他要素。但是,黑莓版本有一些是您从原始版本接手的部分-这些是每种蛋糕必须具备的基本步骤。就像牛奶一样的成分-每个派生阶层都有的。

现在您要交换成分和步骤,这些必须在新版蛋糕中定义。这些是必须为新蛋糕定义的抽象方法,因为蛋糕中应该有水果,但是哪个呢?因此,这次您取黑莓。完成。

继续,您已经扩展了蛋糕,遵循了界面并从中提取了步骤和成分。

评论


这是我最喜欢的任何与PHP相关的比较。这真的很有意义。谢谢!

–cbloss793
19年7月31日在16:19

#8 楼

要添加一些已经非常好的答案:


抽象类使您可以提供一定程度的实现,接口是纯模板。接口只能定义功能,而不能实现它。
任何实现该接口的类都致力于实现其定义的所有方法,或者必须将其声明为抽象。
接口可以帮助管理以下事实:与Java一样,PHP不支持多重继承。 PHP类只能扩展单个父级。但是,您可以使一个类承诺实现所需的任意数量的接口。
type:对于其实现的每个接口,该类都具有相应的类型。因为任何类都可以实现一个接口(或多个接口),所以
接口有效地连接了原本不相关的类型。

一个类可以扩展超类并实现任意数量的接口:

class SubClass extends ParentClass implements Interface1, Interface2 {
    // ...
}




请解释何时应使用接口以及何时应使用抽象类?


当您只需要提供一个没有实现的模板时,可以使用一个接口,并且您要确保实现该接口的任何类将具有与实现该接口的任何其他类相同的方法(至少)。

要为其他对象创建基础时,请使用抽象类(部分构建的类)。扩展您的抽象类的类将使用一些定义或实现的属性或方法:

<?php
// interface
class X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.

// abstract class
class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".
?>



如何将抽象类更改为接口?


这是一个简化的案例/示例。取出所有实施细节。例如,将抽象类从:

abstract class ClassToBuildUpon {
    public function doSomething() {
          echo 'Did something.';
    }
}


更改为:

interface ClassToBuildUpon {
    public function doSomething();
}


#9 楼

从系统的角度来看:


抽象类表示“是”关系。假设我有水果,那么我将有一个Fruits抽象类,它具有共同的责任和共同的行为。
接口表示“应该做”的关系。以我的观点(一个初级开发人员的观点),一个接口应该用一个动作或一个接近动作的名称来命名(对不起,找不到这个词,我不是英语为母语的人)可以说是IEatable。您知道它可以被食用,但是您不知道该吃什么。

从编码的角度来看:


如果对象具有重复的代码,这表明它们具有共同的行为,这意味着您可能需要抽象类来重用代码,而您不能使用接口来实现。
另一个区别是,对象可以实现所需数量的接口。 ,但由于“钻石问题”,您只能拥有一个抽象类(请在此处了解原因!http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem)

我可能

PS:“是一个” /“应该做”是由Vivek Vermani的答案带来的,我并不是要窃取他的答案,只是重用这些术语,因为我喜欢它们!

评论


我相信您要寻找的字是可食用的。

–特拉维斯·韦斯顿(Travis Weston)
2014年5月29日15:33

实际上,我相信它是一个“动词”,一个“在做的单词”

– Grizly
2015年1月8日在2:59

#10 楼

在其他答案中已经精确列出了抽象类和接口之间的技术差异。为了编写面向对象的程序,我想添加一个解释,以便在编写代码时在类和接口之间进行选择。

类应表示实体,而接口应表示行为。

让我们举个例子。计算机监视器是一个实体,应表示为一个类。

class Monitor{
    private int monitorNo;
}


它旨在为您提供显示界面,因此功能应由接口。

interface Display{
    void display();
}


其他答案中也提到了很多其他要考虑的事情,但这是大多数人在编码时忽略的最基本的事情。 br />

评论


PHP没有定义返回类型,OP用PHP标记了这个问题

– Purefan
16-11-22在9:11

#11 楼

只是想添加一个示例,说明何时可能需要同时使用两者。我目前正在编写通用ERP解决方案中绑定到数据库模型的文件处理程序。


我有多个抽象类,它们处理标准任务,还具有一些特殊功能,例如针对不同类别的文件的转换和流传输。
文件访问接口定义了获取,存储和删除文件所需的一组通用方法。

这样,我将拥有用于不同文件的多个模板和一组具有明显区别的通用接口方法。该接口为访问方法提供了正确的类比,而不是基本抽象类所具有的类比。

接下来,当我为不同的文件存储服务制作适配器时,此实现将允许在完全不同的上下文中在其他地方使用该接口。