PHP中的接口是什么?
接口允许您创build定义实现它的类的方法的代码。 但是,您不能将任何代码添加到这些方法。
抽象类允许您执行相同的操作,同时向该方法添加代码。
现在,如果你可以用抽象类实现相同的目标,为什么我们甚至需要接口的概念呢?
我已经被告知它必须与OO理论从C ++到Java,这是PHP的OO的东西是基于。 这个概念在Java中有用,但不在PHP中? 这只是一种避免在抽象类中散布占位符的方法吗? 我错过了什么吗?
整个接口的目的是为了让你灵活地让你的类被迫实现多个接口,但是仍然不允许多inheritance。 从多个类inheritance的问题是多种多样的, 维基百科页面总结得非常好。
接口是一个妥协。 大多数多重inheritance的问题不适用于抽象基类,所以现在大多数现代语言禁用多重inheritance,但是调用抽象基类接口,并允许类“实现”尽可能多的那些。
这个概念在面向对象的编程中非常有用。 对我来说,我认为一个接口是一个契约。 只要我的class级和你的class级就这个方法签名合同达成一致,我们就可以“接口”。 至于抽象类,我认为更多的基类,将某些方法剔除,我需要填写细节。
如果已经有抽象类,为什么还需要一个接口? 防止多重inheritance(可能导致多个已知问题)。
其中一个这样的问题:
“钻石问题”(有时称为“致命的死亡钻石”)是两个B类和C类从Ainheritance而来,D类从B和Cinheritance时产生的模糊性。如果A B和/或C已被覆盖,而D不覆盖它,那么Dinheritance哪个版本的方法:B或C的版本?
来源: https : //en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem
为什么/何时使用接口? 一个例子…世界上所有的汽车都有相同的界面(方法)… AccelerationPedalIsOnTheRight()
, BrakePedalISOnTheLeft()
。 想象一下,每个汽车品牌都会有与其他品牌不同的“方法”。 宝马会在右侧刹车,本田在刹车左侧刹车。 人们将不得不学习如何在每次购买不同品牌的汽车时使用这些“方法”。 这就是为什么在多个“地方”拥有相同的界面是个好主意。
接口为你做了什么(为什么有人甚至使用它)? 一个接口可以防止你犯“错误”(它可以保证所有实现了特定接口的类都将具有接口中的方法)。
// Methods inside this interface, must be implemented in all classes which implement this interface. interface IPersonService { public function Create($personObject); } class MySqlPerson implements IPersonService { public function Create($personObject) { // Create a new person in MySql database. } } class MongoPerson implements IPersonService { public function Create($personObject) { // Mongo database creates a new person differenty then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object). } }
这样, Create()
方法将始终以相同的方式使用。 如果我们使用MySqlPerson
类或者MongoPerson
类,它并不会MongoPerson
。 我们如何使用方法的方式保持不变(界面保持不变)。
例如,它会像这样使用(在我们的代码中的任何地方):
new MySqlPerson()->Create($personObject); new MongoPerson()->Create($personObject);
这样,这样的事情就不会发生:
new MySqlPerson()->Create($personObject) new MongoPerson()->Create($personsName, $personsAge);
记住一个接口并且使用同一个接口比多个不同接口要容易得多。
这样,对于不同的类, Create()
方法的内部可以是不同的,而不会影响调用此方法的“外部”代码。 所有外部代码必须知道Create()
方法有1个参数( $personObject
),因为外部代码将使用/调用方法。 外部代码不关心方法内部发生了什么,只需要知道如何使用/调用它。
你也可以在没有接口的情况下做到这一点,但是如果你使用接口,这是“更安全”(因为它可以防止你犯错误)。 该接口向您保证, Create()
方法将在所有实现该接口的类中具有相同的签名(相同types和相同数量的参数)。 这样你可以确定任何一个实现了IPersonService
接口的类都会有Create()
方法(在这个例子中),并且只需要一个参数( $personObject
)就可以被调用/使用。
实现接口的类必须实现接口所具有的所有方法。
我希望我不要重复太多。
使用一个接口和一个抽象类之间的区别与我的代码组织有关,而不是由语言本身来执行。 在为其他开发人员准备代码时使用它们,以便使其保持在预期的devise模式中。 接口是一种“按合同devise”,你的代码同意响应一组可能来自你没有的代码的API调用。
虽然从抽象类inheritance是一个“是”的关系,这并不总是你想要的,而实现一个接口更像是一个“行为像一个”关系。 这种差异在某些情况下可能非常重要。
例如,假设您有一个抽象类帐户,其中有许多其他类可以扩展(帐户types等等)。 它有一组特定的方法只适用于该types组。 但是,这些帐户子类中的一些实现了可版本化,可列出或可编辑,因此可以将其引入预期使用这些API的控制器中。 控制器不关心它是什么types的对象
相比之下,我也可以创build一个不从Account扩展的对象,比如一个User抽象类,并且仍然实现了Listable和Editable,而不是Versionable,这在这里没有任何意义。
通过这种方式,我在说FooUser子类不是一个帐户,但是它的行为就像一个可编辑的对象。 同样BarAccount从Account延伸,但不是User子类,但是实现了Editable,Listable和Versionable。
将所有可编辑,可列表和可版本的API添加到抽象类本身不仅会混乱和丑陋,而且会复制Account和User中的常用接口,或者强制我的User对象实现Versionable,可能只是抛出一个例外。
接口本质上是您可以创build的蓝图。 它们定义了类必须具有的方法,但是您可以在这些限制外创build额外的方法。
我不确定你的意思是不能将代码添加到方法 – 因为你可以。 你将接口应用于抽象类还是inheritance它的类?
应用于抽象类的接口中的方法需要在抽象类中实现。 然而,将该接口应用于扩展类,该方法只需要在扩展类中实现。 我可能在这里是错的 – 我不尽可能经常使用接口。
我一直认为接口是外部开发人员或额外规则集的模式,以确保事情是正确的。
您将在PHP中使用接口:
- 为了隐藏实现 – build立一个对象类的访问协议,改变底层的实现,而不是在所有使用这个对象的地方重构
- 检查types – 如确保参数具有特定types
$object instanceof MyInterface
- 在运行时强制执行参数检查
- 要将多个行为实现为一个类(构build复杂types)
class Car实现EngineInterface,BodyInterface,SteeringInterface {
start()
,(EngineInterface)或goRight()
,goLeft()
(转向界面)
和其他我现在想不到的事情
第四,这可能是你不能用抽象类来解决的最明显的用例。
从Java的思考:
一个接口说:“这就是所有实现这个特定接口的类都是这样的。”因此,任何使用特定接口的代码都知道可以为这个接口调用什么方法,就这些了。 所以这个接口被用来在类之间build立一个“协议”。
接口不作为类可以扩展的基础,而是作为所需function的映射。
以下是使用抽象类不适合的接口的示例:
比方说,我有一个日历应用程序,允许用户从外部来源导入日历数据。 我将编写类来处理导入每种types的数据源(ical,rss,atom,json)。每个类都将实现一个通用接口,以确保它们都具有我的应用程序获取数据的公共方法。
<?php interface ImportableFeed { public function getEvents(); }
然后,当用户添加一个新的饲料,我可以确定它的饲料的types,并使用为该types开发的类来导入数据。 为导入某个特定提要的数据而编写的每个类都有完全不同的代码,除此之外,类之间可能很less有类似之处,因为它们需要实现允许我的应用程序使用它的接口。 如果我要使用一个抽象类,我可以很容易地忽略这样的事实,即我没有重写getEvents()方法,然后在这个实例中中断我的应用程序,而使用一个接口不会让我的应用程序运行,如果任何方法在接口中定义的类不存在于实现它的类中。 我的应用程序不必关心它使用什么类来从一个提要中获取数据,而只需要获取这些数据所需的方法。
为了更进一步,当我回到我的日历应用程序的目的是添加另一种饲料types时,界面certificate是非常有用的。 使用ImportableFeed接口意味着我可以通过简单地添加实现此接口的新类来继续添加更多导入不同Feedtypes的类。 这使我可以添加大量的function,而不必为我的核心应用程序添加不必要的批量,因为我的核心应用程序只依赖于接口需要的公共方法,所以只要我的新的feed导入类实现了ImportableFeed接口,那么I知道我可以把它放在原处并继续前进。
这只是一个非常简单的开始。 然后,我可以创build另一个接口,可以实现所有我的日历类,从而为类处理的提要types提供更多的特定function。 另一个很好的例子是validationFeedtypes的方法
这超出了这个问题,但是因为我使用了上面的例子:如果以这种方式使用接口,它们会有自己的问题。 我发现自己需要确保从实现的方法返回的输出匹配接口,并实现这个我使用一个IDE来读取PHPDoc块,并添加返回types作为types提示在接口的PHPDoc块然后转化为实现它的具体类。 我的类使用了实现这个接口的类的数据输出,至less知道它会在这个例子中返回一个数组:
<?php interface ImportableFeed { /** * @return array */ public function getEvents(); }
没有太多空间来比较抽象类和接口。 接口是简单的映射,当实现时需要类具有一组公共接口。
在我看来,接口应该优于非function抽象类。 我不会感到惊讶,因为只有一个对象被实例化,而不是parsing两个对象,但是它们会相互影响(尽pipe我不能确定,我不熟悉内部运作OOP PHP)。
确实,与Java相比,接口不太有用/有意义。 另一方面,PHP6会引入更多的types提示,包括返回值的types提示。 这应该为PHP接口增加一些价值。
tl; dr:interfaces定义了一个需要遵循的方法列表(think API),而抽象类提供了一些基本的/通用的function,子类根据特定的需要进行细化。
接口不仅仅是为了确保开发者实现某些方法。 这个想法是,因为这些类保证有某些方法,所以即使你不知道类的实际types,也可以使用这些方法。 例:
interface Readable { String read(); } List<Readable> readables; // dunno what these actually are, but we know they have read(); for(Readable reader : readables) System.out.println(reader.read());
在很多情况下,提供一个基类,抽象与否是没有意义的,因为这些实现差异很大,除了less数几个方法之外,不共享任何共同点。
dynamictypes的语言有“鸭子键入”的概念,你不需要接口; 您可以自由地假定对象具有您要调用的方法。 这适用于静态types语言的问题,其中对象有一些方法(在我的例子中,read()),但是没有实现接口。
我不记得PHP在这方面是不同的,但是在Java中,可以实现多个接口,但不能inheritance多个抽象类。 我会假设PHP的工作方式相同。
在PHP中,你可以使用逗号分隔多个接口(我想,我没有find一个干净的soloution)。
至于多个抽象类,你可以有多个相互扩展的摘要(再次,我不完全确定,但我想我以前曾经见过)。 唯一不能延伸的是最后一堂课。
接口不会给你的代码提供任何性能提升,或者类似的东西,但是它们可以在很大程度上维持它的性能。 确实,可以使用抽象类(甚至是非抽象类)来build立一个到你的代码的接口,但是正确的接口(你用关键字定义的那个接口,只包含方法签名)只是简单的整理和阅读。
话虽如此,我决定在决定是否使用类的接口时使用谨慎。 有时我需要默认的方法实现,或者所有子类通用的variables。
当然,关于多接口实现的观点也是合理的。 如果您有一个实现多个接口的类,则可以将该类的一个对象用作同一应用程序中的不同types。
事实上,你的问题是关于PHP,但是,使事情更有趣。 在PHP中input接口仍然不是非常必要的,在那里你可以给任何方法提供任何东西,而不pipe它的types如何。 你可以静态types的方法参数,但其中一些是打破(string,我相信,导致一些打嗝)。 结合这一点,你不能键入大多数其他的引用,并没有太多的价值试图强制静态types的PHP( 在这一点上 )。 正因为如此, PHP中的接口的价值远远低于更强types的语言。 他们有可读性的好处,但没有别的。 多重实现甚至不是有益的,因为你仍然需要声明方法并将它们赋予实现者。
以下是PHP界面的要点
- 它用于在类中定义所需的no方法[如果你想加载html然后id和名称是必需的,所以在这种情况下,接口包括setID和setName]。
- 接口严格强制类包含其中定义的所有方法。
- 您只能在与公共可访问性接口中定义方法。
- 你也可以像类一样扩展接口。 您可以使用扩展关键字在PHP中扩展接口。
- 扩展多个界面。
- 如果两个共享函数名称相同,则不能实现2个接口。 它会抛出错误。
示例代码:
interface test{ public function A($i); public function B($j = 20); } class xyz implements test{ public function A($a){ echo "CLASS A Value is ".$a; } public function B($b){ echo "CLASS B Value is ".$b; } } $x = new xyz(); echo $x->A(11); echo "<br/>"; echo $x->B(10);