php 接口或抽象类:使用哪一个?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1814821/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Interface or an Abstract Class: which one to use?
提问by Alan Storm
Please explain when I should use a PHP interfaceand when I should use an abstract class?
请解释什么时候应该使用 PHP interface,什么时候应该使用abstract class?
How I can change my abstract classin to an interface?
我如何才能将我的abstract classin更改为interface?
回答by Alan Storm
Use an interface when you want to force developers working in your system (yourself included) to implement a set number of methods on the classes they'll be building.
当您想强制在您的系统中工作的开发人员(包括您自己)在他们将要构建的类上实现一定数量的方法时,请使用接口。
Use an abstract class when you want to force developers working in your system (yourself included) to implement a set numbers of methods andyou want to provide some base methods that will help them develop their child classes.
当您想强制在您的系统中工作的开发人员(包括您自己)实现一组方法,并且您想提供一些基本方法来帮助他们开发他们的子类时,请使用抽象类。
Another thing to keep in mind is client classes can only extend one abstract class, whereas they can implement multiple interfaces. So, if you're defining your behavior contracts in abstract classes, that means each child class may only conform to a single contract. Sometimes this a good thing, when you want to force your user-programmers along a particular path. Other times it would be bad. Imagine if PHP's Countable and Iterator interfaces were abstract classes instead of interfaces.
要记住的另一件事是客户端类只能扩展一个抽象类,而它们可以实现多个接口。因此,如果您在抽象类中定义行为契约,这意味着每个子类可能只符合一个契约。有时这是一件好事,当您想强迫您的用户程序员沿着特定路径前进时。其他时候会很糟糕。想象一下,如果 PHP 的 Countable 和 Iterator 接口是抽象类而不是接口。
One approach that's common when you're uncertain which way to go (as mentioned by cletus below) is to create an interface, and then have your abstract class implement that interface.
回答by kn3l
The differences between an Abstract Classand an Interface:
anAbstract Class和 an的区别Interface:
Abstract Classes
抽象类
An abstract class can provide some functionalityand leave the rest for derived class.
抽象类可以提供一些功能,其余的留给派生类。
The derived class may or may not overridethe concrete functions defined in the base class.
A child class extended from an abstract class should logically be related.
派生类可能会也可能不会覆盖基类中定义的具体函数。
从抽象类扩展的子类在逻辑上应该是相关的。
Interface
界面
An interface cannot contain any functionality. It onlycontains definitions of the methods.
接口不能包含任何功能。它仅包含的方法定义。
The derived class MUST provide code for all the methods defined in the interface.
Completely different and non-related classes can be logically grouped together using an interface.
派生类必须为接口中定义的所有方法提供代码。
完全不同且不相关的类可以使用接口在逻辑上组合在一起。
回答by Vineesh Kalarickal
Why to use abstract classes? The following is a simple example. Lets say we have the following code:
为什么要使用抽象类?下面是一个简单的例子。假设我们有以下代码:
<?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
}
}
Now I give you an apple and you eat it. What does it taste like? It tastes like an apple.
现在我给你一个苹果,你吃掉它。尝起来怎么样?它尝起来像一个苹果。
<?php
$apple = new Apple();
$apple->eat();
// Now I give you a fruit.
$fruit = new Fruit();
$fruit->eat();
What does that taste like? Well, it doesn't make much sense, so you shouldn't be able to do that. This is accomplished by making the Fruit class abstract as well as the eat method inside of it.
那是什么味道?好吧,这没有多大意义,所以你不应该这样做。这是通过使 Fruit 类抽象以及其中的 eat 方法来实现的。
<?php
abstract class Fruit {
private $color;
abstract public function eat(){}
public function setColor($c) {
$this->color = $c;
}
}
?>
An abstract class is just like an interface, but you can define methods in an abstract class whereas in an interface they are all abstract. Abstract classes can have both empty and working/concrete methods. In interfaces, functions defined there cannot have a body. In abstract classes, they can.
抽象类就像接口一样,但是您可以在抽象类中定义方法,而在接口中它们都是抽象的。抽象类可以有空方法和工作/具体方法。在接口中,定义的函数不能有主体。在抽象类中,他们可以。
A real world example:
一个真实世界的例子:
<?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
回答by cletus
Best practice is to use an interface to specify the contract and an abstract class as just one implementation thereof. That abstract class can fill in a lot of the boilerplate so you can create an implementation by just overriding what you need to or want to without forcing you to use a particular implementation.
最佳实践是使用一个接口来指定合约和一个抽象类作为其一个实现。该抽象类可以填充大量样板文件,因此您可以通过覆盖您需要或想要的内容来创建一个实现,而不会强迫您使用特定的实现。
回答by Austen Hoogen
Just to throw this into the mix, but as Cletus mentioned using an interface in conjunction with an abstract class, I often use the interface to clarify my design thinking.
只是为了将其混为一谈,但正如 Cletus 提到的将接口与抽象类结合使用,我经常使用接口来阐明我的设计思想。
For instance:
例如:
<?php
class parser implements parserDecoratorPattern {
//...
}
That way, anyone reading my code (and who knows what a Decorator Pattern is) will know right away a) how I build my parser and b) be able to see what methods are used to implement the decorator pattern.
这样,任何阅读我的代码(并且知道什么是装饰器模式的人)都会立即知道 a) 我如何构建我的解析器和 b) 能够看到使用哪些方法来实现装饰器模式。
Also, and I may be off base here not being a Java/C++/etc programmer, but data types can come into play here. Your objects are of a type, and when you pass them around the type matters programmatically. Moving your contractable items into the interface only dictates the types that the methods return, but not the base type of the class that implements it.
另外,我可能不是 Java/C++/etc 程序员,但数据类型可以在这里发挥作用。你的对象是一种类型,当你以编程方式传递它们时,类型很重要。将您的可收缩项移动到接口中仅指示方法返回的类型,而不是实现它的类的基类型。
It's late and I can't think of a better psudo-code example, but here goes:
已经晚了,我想不出更好的伪代码示例,但这里是:
<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)
回答by Mitch Wheat
The main difference is an abstract class can contain default implementation whereas an interface cannot.
主要区别在于抽象类可以包含默认实现,而接口不能。
An interface is a contract of behaviour without any implementation.
接口是没有任何实现的行为契约。
回答by Thielicious
Also, just would like to add here that just because any other OO language has some kind of interfaces and abstraction too doesn't mean they have the same meaning and purpose as in PHP. The use of abstraction/interfaces is slightly different while interfaces in PHP actually don't have a real function. They merely are used for semantic and scheme-related reasons. The point is to have a project as much flexible as possible, expandable and safe for future extensions regardless whether the developer later on has a totally different plan of use or not.
另外,我想在这里补充一点,仅仅因为任何其他 OO 语言也具有某种接口和抽象,并不意味着它们与 PHP 具有相同的含义和目的。抽象/接口的使用略有不同,而 PHP 中的接口实际上没有真正的功能。它们仅用于语义和与方案相关的原因。关键是让项目尽可能灵活、可扩展且安全,以供未来扩展,无论开发人员以后是否有完全不同的使用计划。
If your English is not native you might lookup what Abstraction and Interfaces actually are. And look for synonyms too.
如果您的英语不是母语,您可能会查找抽象和接口实际上是什么。并寻找同义词。
And this might help you as a metaphor:
这可能会帮助你作为一个比喻:
INTERFACE
界面
Let's say, you bake a new sort of cake with strawberries and you made up a recipe describing the ingredients and steps. Only you know why it's tasting so well and your guests like it. Then you decide to publish your recipe so other people can try that cake as well.
比方说,你用草莓烤了一种新的蛋糕,你制作了一个描述成分和步骤的食谱。只有您知道为什么它的味道如此好并且您的客人喜欢它。然后您决定发布您的食谱,以便其他人也可以尝试该蛋糕。
The point here is
这里的重点是
- to make it right
- to be careful
- to prevent things which could go bad (like too much strawberries or something)
- to keep it easy for the people who try it out
- to tell you how long is what to do (like stiring)
- to tell which things you CAN do but don't HAVE to
- 使其正确
- 小心
- 防止可能变坏的事情(例如草莓过多或其他东西)
- 让尝试它的人容易
- 告诉您该做什么(例如搅拌) )
- 告诉你哪些事情你可以做但不必做
Exactly THIS is what describes interfaces. It is a guide, a set of instructions which observe the content of the recipe. Same as if you would create a project in PHP and you want to provide the code on GitHub or with your mates or whatever. An interface is what people can do and what you should not. Rules that hold it - if you disobey one, the entire construct will be broken.
这正是描述接口的内容。它是一个指南,一组观察配方内容的说明。就像您在 PHP 中创建一个项目并且您想在 GitHub 上或与您的伙伴或其他任何人一起提供代码一样。界面是人们可以做什么和不应该做什么。持有它的规则 - 如果您不遵守其中的规则,则整个构造将被破坏。
ABSTRACTION
抽象
To continue with this metaphor here... imagine, you are the guest this time eating that cake. Then you are trying that cake using the recipe now. But you want to add new ingredients or change/skip the steps described in the recipe. So what comes next? Plan a different version of that cake. This time with black berries and not straw berries and more vanilla cream...yummy.
在这里继续这个比喻……想象一下,这次你是吃那个蛋糕的客人。那么你现在正在使用食谱尝试那个蛋糕。但是您想添加新成分或更改/跳过食谱中描述的步骤。那么接下来会发生什么呢?计划一个不同版本的蛋糕。这次是黑浆果而不是草莓,还有更多的香草奶油……很好吃。
This is what you could consider an extension of the original cake. You basically do an abstraction of it by creating a new recipe because it's a lil different. It has a few new steps and other ingredients. However, the black berry version has some parts you took over from the original - these are the base steps that every kind of that cake must have. Like ingredients just as milk - That is what every derived class has.
这是你可以考虑的原始蛋糕的延伸。你基本上是通过创建一个新的配方来抽象它,因为它有点不同。它有一些新的步骤和其他成分。然而,黑莓版本有一些你从原版中接管的部分——这些是每种蛋糕都必须具备的基本步骤。就像牛奶一样的成分 - 这是每个派生类都有的。
Now you want to exchange ingredients and steps and these MUST be defined in the new version of that cake. These are abstract methodswhich have to be defined for the new cake, because there should be a fruit in the cake but which? So you take the black berries this time. Done.
现在你想交换原料和步骤,这些必须在那个蛋糕的新版本中定义。这些是必须为新蛋糕定义的抽象方法,因为蛋糕中应该有一个水果,但是哪个?所以这次你吃黑莓。完毕。
There you go, you have extended the cake, followed the interface and abstracted steps and ingredients from it.
好了,您已经扩展了蛋糕,遵循了界面并从中提取了步骤和成分。
回答by bg17aw
To add to some of the already excellent answers:
添加一些已经很好的答案:
Abstract classes let you provide some degree of implementation, interfaces are pure templates. An interface can only define functionality, it can never implement it.
Any class that implements the interface commits to implementing all the methods it defines or it must be declared abstract.
Interfaces can help to manage the fact that, like Java, PHP does not support multiple inheritance. A PHP class can only extend a single parent. However, you can make a class promise to implement as many interfaces as you want.
type: for each interface it implements, the class takes on the corresponding type. Because any class can implement an interface (or more interfaces), interfaces effectively join types that are otherwise unrelated.
a class can both extend a superclass and implement any number of interfaces:
class SubClass extends ParentClass implements Interface1, Interface2 { // ... }
抽象类让你提供某种程度的实现,接口是纯模板。一个接口只能定义功能,它永远无法实现它。
任何实现接口的类都承诺实现它定义的所有方法,或者它必须被声明为抽象的。
接口可以帮助管理这样一个事实,即与 Java 一样,PHP 不支持多重继承。PHP 类只能扩展一个父类。但是,您可以让类承诺实现任意数量的接口。
类型:对于它实现的每个接口,该类采用相应的类型。因为任何类都可以实现一个接口(或多个接口),所以接口可以有效地连接不相关的类型。
一个类既可以扩展超类,也可以实现任意数量的接口:
class SubClass extends ParentClass implements Interface1, Interface2 { // ... }
Please explain when I should use an interface and when I should use abstract class?
请解释什么时候应该使用接口,什么时候应该使用抽象类?
Use an interface when you need to provide only a template with no implementation what so ever, and you want to make sure any class that implements that interface will have the same methods as any other class that implements it (at least).
当您只需要提供一个没有实现的模板时使用接口,并且您想确保实现该接口的任何类都将具有与实现它的任何其他类(至少)相同的方法。
Use an abstract class when you want to create a foundation for other objects (a partially built class). The class that extends your abstract class will use some properties or methods defined/implemented:
当您想为其他对象(部分构建的类)创建基础时,请使用抽象类。扩展抽象类的类将使用一些定义/实现的属性或方法:
<?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".
?>
How I can change my abstract class in to an interface?
如何将抽象类更改为接口?
Here is a simplified case/example. Take out any implementation details out. For example, change your abstract class from:
这是一个简化的案例/示例。取出任何实现细节。例如,将您的抽象类从:
abstract class ClassToBuildUpon {
public function doSomething() {
echo 'Did something.';
}
}
to:
到:
interface ClassToBuildUpon {
public function doSomething();
}
回答by IEatBagels
From a phylosophic point of view :
从哲学的角度来看:
An abstract class represents an "is a" relationship. Lets say I have fruits, well I would have a Fruit abstract class that shares common responsabilities and common behavior.
An interface represents a "should do" relationship. An interface, in my opinion (which is the opinion of a junior dev), should be named by an action, or something close to an action, (Sorry, can't find the word, I'm not an english native speaker) lets say IEatable. You know it can be eaten, but you don't know what you eat.
抽象类表示“是一个”关系。假设我有水果,那么我会有一个 Fruit 抽象类,它具有共同的责任和共同的行为。
接口表示“应该做”的关系。一个界面,在我看来(这是一个初级开发者的意见),应该以一个动作或接近动作的东西命名,(对不起,找不到这个词,我不是英语母语者)让我们说IEatable。你知道它可以吃,但你不知道你吃什么。
From a coding point of view :
从编码的角度来看:
If your objects have duplicated code, it is an indication that they have common behavior, which means you might need an abstract class to reuse the code, which you cannot do with an interface.
Another difference is that an object can implement as many interfaces as you need, but you can only have one abstract class because of the "diamond problem" (check out here to know why! http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem)
如果您的对象具有重复的代码,则表明它们具有共同的行为,这意味着您可能需要一个抽象类来重用代码,而使用接口则无法做到这一点。
另一个区别是,一个对象可以根据需要实现多个接口,但由于“钻石问题”,您只能拥有一个抽象类(请查看此处了解原因!http://en.wikipedia.org/wiki/ Multiple_inheritance#The_diamond_problem)
I probably forget some points, but I hope it can clarify things.
我可能忘记了一些要点,但我希望它可以澄清一些事情。
PS : The "is a"/"should do" is brought by Vivek Vermani's answer, I didn't mean to steal his answer, just to reuse the terms because I liked them!
PS:“是一个”/“应该做”是Vivek Vermani的回答带来的,我不是故意偷他的答案,只是因为我喜欢它们而重复使用这些术语!
回答by Anurag Sharma
The technical differences between an abstract class and an interface are already listed in the other answers precisely. I want to add an explanation to choose between a class and an interface while writing the code for the sake of object oriented programming.
抽象类和接口之间的技术差异已经在其他答案中准确列出。为了面向对象编程,我想在编写代码时添加解释以在类和接口之间进行选择。
A class should represent an entity whereas an interface should represent the behavior.
一个类应该代表一个实体,而一个接口应该代表行为。
Let's take an example. A computer monitor is an entity and should be represented as a class.
让我们举个例子。计算机监视器是一个实体,应该表示为一个类。
class Monitor{
private int monitorNo;
}
It is designed to provide a display interface to you, so the functionality should be defined by an interface.
它旨在为您提供显示界面,因此功能应由界面定义。
interface Display{
void display();
}
There are many other things to consider as explained in the other answers, but this is the most basic thing which most of the people ignore while coding.
如其他答案中所述,还有许多其他事情需要考虑,但这是大多数人在编码时忽略的最基本的事情。

