什么时候在PHP中使用Final?

时间:2010-11-22 17:02:56

标签: php oop final

我知道Final类的定义是什么,但我想知道如何以及何时真正需要final。

<?php
final class Foo extends Bar
{
   public function()
   {
     echo 'John Doe';
   }
}

如果我理解正确,'final'使它能够扩展'Foo'。

任何人都可以解释何时以及为什么应该使用'final'?换句话说,是否有任何理由不应该扩展课程?

例如,如果类'Bar'和类'Foo'缺少某些功能,那么创建一个扩展'Bar'的类会很好。

5 个答案:

答案 0 :(得分:44)

有一篇关于"When to declare classes final"的好文章。引用的一些引用:

  

TL; DR:如果他们实现了一个接口,并且没有定义其他公共方法,则使您的课程始终为final

     

为什么我必须使用final

     
      
  1. 防止大规模的厄运继承链
  2.   
  3. 鼓励作文
  4.   
  5. 强制开发人员考虑用户公共API
  6.   
  7. 强制开发人员缩小对象的公共API
  8.   
  9. final类始终可以扩展
  10.   
  11. extends打破封装
  12.   
  13. 您不需要这种灵活性
  14.   
  15. 您可以自由更改代码
  16.         

    何时避免final

         

    最终课程只能在以下假设下有效运作:

         
        
    1. 最后一个类实现了一个抽象(接口)
    2.   
    3. 最终类的所有公共API都是该接口的一部分
    4.         

      如果缺少这两个前提条件中的一个,那么您可能会到达可以使类可扩展的时间点,因为您的代码并不真正依赖于抽象。

P.S。感谢@ocramius的精彩阅读!

答案 1 :(得分:18)

对于一般用法,我建议不要将课程设为“最终”。可能存在一些有意义的用例:如果您设计一个复杂的API /框架并希望确保框架的用户只能覆盖您希望他们控制的功能部分,那么您可能有意义限制这种可能性并使某些基类最终。

e.g。如果你有一个“整数”类,那么为了让你的框架形式的用户覆盖你的班级中的“add(...)”方法,最后做出决定是有意义的。

答案 2 :(得分:10)

原因是:

  
      
  1. 将一个类声明为final可防止它成为子类化的句点;这是该行的结束。

  2.   
  3. 将类中的每个方法声明为final都允许创建子类,这些子类可以访问父类的方法,但不能覆盖它们。子类可以定义自己的其他方法。

  4.   
  5. final关键字仅控制覆盖的功能,不应与私有可见性修饰符混淆。任何其他类都无法访问私有方法;最后一个可以。

  6.   

- 引自 David Powers PHP面向对象解决方案一书的第68页。

例如:

final childClassname extends ParentsClassname {
    // class definition omitted
}

这涵盖了整个班级,包括其所有方法和属性。从childClassname创建子类的任何尝试现在都会导致致命错误。   但是,如果您需要允许类被子类化但是阻止覆盖特定方法,则final关键字会出现在方法定义的前面。

class childClassname extends parentClassname { 
    protected $numPages;

    public function __construct($autor, $pages) {
        $this->_autor = $autor;
        $this->numPages = $pages;
    }

    final public function PageCount() { 
        return $this->numPages; 
    }
}

在此示例中,它们都不能覆盖PageCount()方法。

答案 3 :(得分:5)

最后一堂课是无法展开的课程http://www.php.net/manual/en/language.oop5.final.php

您可以在类包含您特别不希望被覆盖的方法的地方使用它。这可能是因为这样做会以某种方式破坏您的应用程序。

答案 4 :(得分:-2)

我的 2 美分:

何时使用 final

  • 从不!!

为什么?

  • 它破坏了单元测试时使用测试替身的能力
  • 由于下游代码中的功能存在差距,可能会导致代码重复增加
  • 使用它的原因是所有的训练问题都可以通过一个激进的捷径来解决

使用它的不良理由:

  • 防止厄运的大规模继承链(训练问题)
  • 鼓励作文(培训问题)
  • 迫使开发者考虑用户公共 API (培训问题)
  • 强制开发者缩小对象的公共 API (培训问题?代码审查?)
  • 最终类总是可以扩展的(相关性?)
  • 扩展破坏封装(什么?糟糕的封装破坏了封装;不是继承。继承本质上不是邪恶的。)
  • 您不需要这种灵活性(短视开发背后的典型想法。准备好遇到功能墙+培训问题)
  • 您可以随意更改代码(相关性?)