请解释一下什么时候我应该使用PHP接口,什么时候我应该使用抽象类?
我如何能改变我的抽象类在一个接口?
请解释一下什么时候我应该使用PHP接口,什么时候我应该使用抽象类?
我如何能改变我的抽象类在一个接口?
当前回答
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.
如果你的英语不是母语,你可以查一下抽象和接口到底是什么。还要注意同义词。
这也许可以作为一个比喻:
接口
比方说,你用草莓烤了一种新的蛋糕,你还写了一份食谱,描述了配料和步骤。 只有你自己知道为什么它的味道这么好,你的客人喜欢它。 然后你决定公布你的食谱,这样其他人也可以尝试这个蛋糕。
这里的重点是
-为了弥补错误 -小心 防止事情变坏(比如草莓吃多了之类的) -让尝试的人容易上手 -告诉你要做多长时间(比如搅拌) ——告诉你哪些事情你可以做,但不必做
这就是接口的描述。它是一份指南,一套遵守食谱内容的说明。 就像你要用PHP创建一个项目,你想把代码提供给GitHub或你的伙伴或其他什么。 界面是指人们可以做什么,你不应该做什么。如果你不遵守其中一条,整个结构就会被打破。
抽象
继续这个比喻……想象一下,这次你是吃蛋糕的客人。那你现在就用这个食谱做蛋糕。 但你想添加新的食材或更改/跳过食谱中描述的步骤。那么接下来会发生什么?计划一个不同版本的蛋糕。 这次用的是黑莓,不是草莓,更多的香草奶油…
这是你可以考虑的原始蛋糕的扩展。你基本上是通过创建一个新食谱来对它进行抽象,因为它有点不同。它有一些新的步骤和其他成分。然而,黑莓蛋糕的一些部分是你从原来的蛋糕中继承来的——这些是每种蛋糕都必须具备的基本步骤。就像牛奶一样的成分-这是每个派生类都有的。
现在你想要交换原料和步骤,这些必须在新版本的蛋糕中定义。这些都是抽象方法,必须为新蛋糕定义,因为蛋糕中应该有水果,但是是哪个呢?所以这次你选黑莓。完成了。
好了,你已经扩展了蛋糕,遵循了界面,并从中提取了步骤和成分。
其他回答
最佳实践是使用接口来指定契约,并将抽象类作为契约的一个实现。该抽象类可以填充大量样板文件,因此您可以通过重写需要或想要的内容来创建实现,而不必强制使用特定的实现。
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.
如果你的英语不是母语,你可以查一下抽象和接口到底是什么。还要注意同义词。
这也许可以作为一个比喻:
接口
比方说,你用草莓烤了一种新的蛋糕,你还写了一份食谱,描述了配料和步骤。 只有你自己知道为什么它的味道这么好,你的客人喜欢它。 然后你决定公布你的食谱,这样其他人也可以尝试这个蛋糕。
这里的重点是
-为了弥补错误 -小心 防止事情变坏(比如草莓吃多了之类的) -让尝试的人容易上手 -告诉你要做多长时间(比如搅拌) ——告诉你哪些事情你可以做,但不必做
这就是接口的描述。它是一份指南,一套遵守食谱内容的说明。 就像你要用PHP创建一个项目,你想把代码提供给GitHub或你的伙伴或其他什么。 界面是指人们可以做什么,你不应该做什么。如果你不遵守其中一条,整个结构就会被打破。
抽象
继续这个比喻……想象一下,这次你是吃蛋糕的客人。那你现在就用这个食谱做蛋糕。 但你想添加新的食材或更改/跳过食谱中描述的步骤。那么接下来会发生什么?计划一个不同版本的蛋糕。 这次用的是黑莓,不是草莓,更多的香草奶油…
这是你可以考虑的原始蛋糕的扩展。你基本上是通过创建一个新食谱来对它进行抽象,因为它有点不同。它有一些新的步骤和其他成分。然而,黑莓蛋糕的一些部分是你从原来的蛋糕中继承来的——这些是每种蛋糕都必须具备的基本步骤。就像牛奶一样的成分-这是每个派生类都有的。
现在你想要交换原料和步骤,这些必须在新版本的蛋糕中定义。这些都是抽象方法,必须为新蛋糕定义,因为蛋糕中应该有水果,但是是哪个呢?所以这次你选黑莓。完成了。
好了,你已经扩展了蛋糕,遵循了界面,并从中提取了步骤和成分。
为什么要使用抽象类?下面是一个简单的例子。假设我们有以下代码:
<?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
再加上一些已经很好的答案:
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 { // ... }
请解释什么时候我应该使用接口,什么时候我应该使用抽象类?
当您只需要提供一个模板而不需要任何实现时,请使用接口,并且您希望确保实现该接口的任何类(至少)与实现该接口的任何其他类具有相同的方法。
当您想要为其他对象(部分构建的类)创建基础时,请使用抽象类。扩展抽象类的类将使用一些定义/实现的属性或方法:
<?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.';
}
}
to:
interface ClassToBuildUpon {
public function doSomething();
}
只是把这一点加入到混合中,但正如Cletus提到的将接口与抽象类结合使用一样,我经常使用接口来阐明我的设计思维。
例如:
<?php
class parser implements parserDecoratorPattern {
//...
}
这样,任何阅读我的代码(并且知道Decorator Pattern是什么)的人都将立即知道a)我如何构建我的解析器和b)能够看到使用哪些方法来实现Decorator模式。
此外,我可能不是Java/ c++ /等程序员,但数据类型可以在这里发挥作用。你的对象是一个类型,当你传递它们时,类型在编程上很重要。将可收缩项移动到接口中只指定方法返回的类型,但不指定实现它的类的基类型。
现在已经很晚了,我想不出一个更好的伪代码示例,但如下所示:
<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)