为什么PHP有接口?


35

我注意到从PHP5开始,接口已添加到该语言中。但是,由于PHP的类型过于宽松,因此似乎失去了使用接口的大多数好处。为什么这包括在语言中?


5
我认为正确的问题是,为什么不呢?
·费尔南德斯

5
因为它们似乎没有提供任何好处,那么为什么要包括它们呢?
GSto 2011年

4
@HorusKol,在实现它们之前,它们没有被使用过,因此您可以看到它们在以前的版本中是如何未使用和无用的。您还必须提出并支持声称使用它们在某种程度上说它们是有用的改进。
Rein Henrichs

6
@HorusKol一点也不似是而非。证明锤子的价值主张很容易。这个问题是要有人证明PHP接口的价值主张,而不仅仅是以争论的方式宣称它们是有价值的。
Rein Henrichs

3
请记住,接口不仅仅与打字有关。接口是一种合同,规定实现类必须包括其布局的方法。对于插件引擎等有用。
迈克尔(Michael)

Answers:


30

PHP接口的主要优点是类可以实现多个接口。这使您可以对共享某些功能但不必共享父类的类进行分组。一些示例可能包括以某种方式缓存,输出或访问类的属性。

在您的代码中,您可以检查类是否实现了给定的接口,而不必检查类名。然后,添加新类后,您的代码仍然可以使用。

PHP提供了一些可以在各种情况下派上用场的预定义接口:http : //php.net/manual/en/reserved.interfaces.php

编辑-添加示例

如果您有一个名为MyInterface的接口,并且正在使用不同类的多个对象,这些对象可能会或可能不会共享某些功能,则接口可以使您执行以下操作:

// Assume $objects is an array of instances of various classes
foreach($objects as $obj) {
 if($obj instanceof MyInterface) {
     $obj->a();
     $obj->b();
     $obj->c();
   }
}

23
换句话说:“您可以完全忽略动态类型语言的所有好处”
KamilTomšík,2011年

11
@Kamil,我认为它更多的是能够利用静态类型的好处而不会在您不需要它们时带来缺点。
Karl Bielefeldt

9
你是认真的吗?instanceof?如果一直那么一直,那听起来不熟悉吗?嗯,是的,过程编程。
卡米尔·汤姆斯克(KamilTomšík),2011年

23
@KamilTomšík另一个侮辱PHP语言的人,而不是那些使用不熟练的人的语言。PHP具有用于完整的面向对象编程的所有工具。是否使用它们取决于程序员。此外,过程编程本身没有任何问题。
Lotus Notes

18
@Kamil-多么奇怪,通过阅读您的评论,您可能会得出结论,即OOP中没有if-s,并且某种程度上,魔术地起作用了。哇。
Michael JV

23

PHP是松散类型的,但对于诸如方法参数之类的东西,可以强类型化。

考虑以下示例:

interface Car { function go(); }

class Porsche { function go() {} }

function drive(Car $car) {}

$porsche = new Porsche();

drive($porsche);

上面的代码将输出:

传递给drive()的参数1必须实现接口Car,保时捷实例已给定


1
当然,这太糟糕了。不过,您可以null为参数设置默认值。
Emanuil Rusev 2011年

5
但是如果drive需要Car,那么null无论如何传递并不会很有帮助...
HorusKol 2011年

7
永远不要传递null。使用“特殊情况”对象(Google对Martin Fowler的解释)。
马丁·布洛

2
@Renesis如果将默认值设置为null,则可以将null传递给类型提示的方法。(CAR $ car = null)将允许您使用null作为参数来调用此方法。但是,这将是非常愚蠢的做法。您到底为什么要能够做到这一点?
dqhendricks

2
具体示例: function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);您可能有一个,$methodName但没有$securityMode
妮可(Nicole)

7

接口使您可以实现开闭原理,维护松散耦合的代码库以及实现许多最佳的OOP设计模式。

例如,如果一个类接受另一个类作为参数:

class A {

    public function __construct(B $class_b) {
        // use class b
        $class_b->run();
    }
}

现在,您的A类和B类紧密耦合,并且A类不能使用除B类之外的任何其他类。类型提示可确保您具有正确的参数类型,但现在巩固了A和B之间的关系。

假设您希望类A能够使用所有具有run()方法的类。这基本上是(但不是完全)COMMAND设计模式。要解决此问题,您可以使用接口而不是具体的类来键入提示。B将实现该接口,并将其作为类A的参数接受。这样,类A可以接受使用该接口作为其构造函数参数的任何类。

大多数OOP设计模式都使用这种类型的编码,并且可以在以后的某个时间更轻松地更改代码。这些是AGILE编程基础知识的一部分。


1
或B的任何子类
Mez 2012年

7

@pjskeptic有一个很好的答案,而@KamilTomšík对这个答案有很好的评论。

关于动态类型化语言(如PHP)的妙处在于,您可以尝试在对象上使用方法,除非该方法不存在,否则它不会对您大喊大叫。

像PHP这样的动态类型化语言的问题在于,您可以尝试在对象上使用方法,当方法不存在时,它会大喊大叫。

接口增加了一种方便的方法来调用未知对象上的方法,并确定方法是否存在(不一定是正确的或不会起作用的)。它不是语言的必要部分,但是它使编码更加方便。它允许强类型的OOP开发人员编写强类型的PHP代码,然后可以与其他PHP开发人员编写的松类型的PHP代码一起使用。

类似的功能:

foo( IBar $bar )
{
  $baz = $bar->baz();
  ...
}

比:

foo( $bar )
{
  if ( method_exists( $bar, 'baz' ) )
  {
    $baz = $bar->baz();
  }
  else
  {
    throw new Exception('OMGWTF NO BAZ IN BAR!');
  }
  ...
}

恕我直言,简单易读的代码是更好的代码。


1
相反,您要做的就是不检查方法,当有人用错误的数据调用您的函数时崩溃并刻录。如果有人错误使用您的函数,这不是您的问题。
雷诺斯2011年

没有确切-你的例子是噩梦的人谁想要传递的任何动态“鸭”,如代理,适配器,装饰等
卡米尔Tomšík

1
@Kamil?为何如此。代理将是某种包装器类,用于某些未实现接口以使其不能与该函数一起使用的接口。
tylermac 2011年

@tylermac使用__call()的动态代理-如果__call是那里的唯一方法,则它根本无法实现IBar,这意味着您无法将其传递给foo(IBar $ bar)
KamilTomšík2011年

5

如果您使用的是鸭式打字机,它们是完全没有用的,实际上,当您进行鸭式打字时,使用使用任何类型提示的库/框架会很烦人。

这也适用于各种动态元编程(魔术方法)。


3

PHP 不是宽松或强壮的,而是动态类型的

关于接口,您应该问自己的第一件事是:接口的最大好处是什么?

在OOP中,接口不仅与类型有关,而且与行为有关。

由于PHP还具有类型提示功能,因此您可以像使用纯oo语言(例如Java)一样使用接口。

interface File
{
    public function getLines();
}

CSVFile implements File
{
    public function getLines()
    {}
}

XMLFile implements File 
{
    public function getLines()
    {}
}

JSONFile implements File 
{
    public function getLines()
    {}
}

class FileReader
{
    public function read(File $file)
    {
        foreach($file->getLines() as $line)
        {
            // do something
        }
    }
}

使用PHP接口实现,您还可以使用PHPUnit为抽象类创建模拟 -这真是个特性:

public function testSomething()
{
    $mock = $this->getMockForAbstractClass('File');

    $mock->expects($this->once())
         ->method('getLines')
         ->will($this->returnValue(array()));

    // do your assertions
}

因此,基本上,您可以使用语言功能(其中之一是接口)来在PHP中使用SOLID兼容的应用程序。


0

接口对依赖项注入的作用远比具体的有用。作为一个简单的例子:

interface Istore { 
  public function save(); 
}

class Article_DB implements Istore 
{ 
  public function save($data) 
  {
    // do save to format needed.
  } 
}

class Article
{
   private $content;

   public function content($content)
   {
     $this->content = $content;
   }

   public function save(Istore $store)
   {
     $store->save($this->content);
   }
}

$article = new Article();
$article->content('Some content');

$store = new Article_DB();
$article->save($store);

现在说一下,如果您的需求发生变化,并且想要保存为pdf。您可以为此目的创建一个新类,而不用污染Article类。

class Article_PDF implements Istore 
{ 
  public function save($data) 
  {
    // do save to format needed.
  } 
}


$article = new Article();
$article->content('Some content');

$store = new Article_PDF();
$article->save($store);

现在,Article类具有一个合同,用于保存的类必须实现Istore接口。它不在乎其保存位置或保存方式。


-1

您可以提供实现接口的“伪”真实对象。然后,您可以对部分代码进行单元测试,而无需实际的服务器,文件系统,套接字,数据库等。


-3

很多人可能会讨厌我以这种方式回答问题,但是使用PHP可以轻松解决输入问题的解决方案。是的, PHP是松散类型的,因此默认情况下采用类型,这引起一些问题,尤其是在比较操作中,这是大多数人的问题。话虽这么说,如果将使用的内容转换为所需的类型,然后使用按位比较运算符,PHP可以与任何强类型语言一样严格。这是我能想到的最简单的示例:

$ myVar =(int)0; $ myOtherVar ='0';

比较($ myVar == $ myVar)等于(布尔)true

但是比较($ myVar === $ myVar)等于(bool)false,就像任何“类型化”比较一样

我真的希望开发人员不要再争论这些事情,如果您对PHP的工作方式有疑问,要么在Java中运行程序,然后开始生存,要么以其实现您想要的方式使用它。反正它对你有什么好处?给你借口整天缠着吗?使你看起来比别人好吗?好吧,您对自己感到如此高度,以至于愿意让别人看起来很糟,但实际上,这是您的偏好,并强迫您相信任何人,实际上只会使他们以不适应导致三件事的方式进行编码:

1)他们将按照您的方式进行编码,但是按照您的标准“混乱”(想想,您是否见过Java程序员创建了他们的第一个PHP程序,反之亦然?这与改变他们的方法论一样,甚至更糟。)

2)您会发现其他值得抱怨的地方

3)它们可能需要更长的时间才能生产。也许这会使您在短期内看起来更好,但是整个团队的情况会更糟(请记住,您的编码可能比其他人慢,并且只要团队在合理的时间范围内满足可交付成果,这并不一定很糟糕,但是将您的习惯强加给通常表现得更快的人,可能最终会使您的整个团队变慢,因此,在非常苛刻的工作流程中看起来更糟)

我个人更喜欢编写过程PHP代码,尽管我可以并且已经使用OOP以几种不同的语言编写了完整的程序。话虽这么说,我已经看到了好的OOP代码和不好的OOP代码,以及好的过程代码和不好的过程代码……确实与实践无关,但与您所使用的习惯有关,即使如此,很多事情是我的解释……这并不意味着我要对那些开发人员说不好,也不要说“我的方法是最好的” BS吹牛,这对我来说是正确的,而且我工作的公司很漂亮我为自己的工作感到高兴,对此我感到自豪。有理由应该建立一个标准,但是您选择的标准中包含的内容非常重要...感谢您让我从中脱颖而出。祝你有美好的一天。


-4
  1. 接口是OOP范例的一部分。因此,当您尝试制作面向对象的零件或系统时,它在许多情况下非常有用。
  2. 所以。为什么不?;-)

示例:您需要缓存数据。怎么样?缓存有很多不同的引擎,哪个是最好的?谁在乎您是否拥有抽象层,该抽象层具有一些ICacheDriver接口以及一组诸如key,get,put,clear等方法。只需对其实施当前项目中需要的内容,并在需要时进行更改即可。还是toString的简单用法。您有一组不同的可显示对象。您只需实现Stringable接口(它描述了toString方法[[在PHP中没有真正的接口,例如,]]),然后使用(string)$ obj遍历所有对象。除了切换(true),您还需要做所有事情。{case $ obj nottanceof A1:“ do 1”; 打破; ...}

简单。因此,毫无疑问“为什么?”。有“如何更好地利用它?”。;-) 祝好运。


-5

我猜。

PHP被许多入门级程序员使用,入门级程序员在大学里被教过Java

在他们的101编程课程之后,他们开始na他们想要Java功能的Zend,因为那是他们被认为思考的方式,以您自己的方式思考(或理解鸭子的打字)很难,而您只有20岁。

Zend务实,添加功能比假装它们始终容易得多。
这也吸引了更多的用户,而不是让他们离开,所以这一定是好的。

此过程的另一个实例?刚接触.NET和Java课程的人们也希望使用基础类框架,他们对此na不已,直到Zend发芽Zend框架。这会吸引更多的用户。等等……

(多年来,PHP团队一直在与之抗争的唯一语言功能是goto


在我看来,它PHP12可能具有世界上所有的语法功能(我希望它不会有一个抽象层运行时,很难,因为那是杀死perl的原因),并且对功能和数据类型范例有所了解,但仍然没有goto
ZJR 2012年

“当您只有20岁时,这很困难”年龄与理解这些概念可能有什么关系?
Evicatos

@Evicatos高中生会选择类似的程序,但他们通常会有糟糕的老师,糟糕的命名约定并产生难以维护的斑点。他们学习编程的权利,而进入大学,它需要几年得到它去。然后,它们开始与最初几年曾教过的硬类型,行业有福,受到社会广泛赞誉的语言有所不同,然后转向更为实用的鸭子式语言。我相信这是许多程序员共享的武士道。再说一次,这可能无法反映您的经验,您可能是一名自学成才的贤才。如果是这样,请告诉我们。
ZJR 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.