67

I know what the definition is of a Final class, but I want to know how and when final is really needed.

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

If I understand it correctly, 'final' enables it to extend 'Foo'.

Can anyone explain when and why 'final' should be used? In other words, is there any reason why a class should not be extended?

If for example class 'Bar' and class 'Foo' are missing some functionality, it would be nice to create a class which extends 'Bar'.

Charles
  • 50,943
  • 13
  • 104
  • 142
Inga Johansson
  • 771
  • 1
  • 5
  • 8

5 Answers5

73

There is a nice article about "When to declare classes final". A few quotes from it:

TL;DR: Make your classes always final, if they implement an interface, and no other public methods are defined

Why do I have to use final?

  1. Preventing massive inheritance chain of doom
  2. Encouraging composition
  3. Force the developer to think about user public API
  4. Force the developer to shrink an object's public API
  5. A final class can always be made extensible
  6. extends breaks encapsulation
  7. You don't need that flexibility
  8. You are free to change the code

When to avoid final:

Final classes only work effectively under following assumptions:

  1. There is an abstraction (interface) that the final class implements
  2. All of the public API of the final class is part of that interface

If one of these two pre-conditions is missing, then you will likely reach a point in time when you will make the class extensible, as your code is not truly relying on abstractions.

P.S. Thanks to @ocramius for great reading!

Nikita U.
  • 3,540
  • 1
  • 28
  • 37
25

For general usage, I would recommend against making a class final. There might be some use cases where it makes sense: if you design a complex API / framework and want to make sure that users of your framework can override only the parts of the functionality that you want them to control it might make sense for you to restrict this possibility and make certain base classes final.

e.g. if you have an Integer class, it might make sense to make that final in order to keep users of your framework form overriding, say, the add(...) method in your class.

Yousha Aleayoub
  • 4,532
  • 4
  • 53
  • 64
mhanisch
  • 580
  • 3
  • 4
  • 5
    It has often surprised me in the past just how often I have needed to do ridiculous things which were blocked casually, like your Integer class example. Granted, each time it's happened it has been the product of weeks of careful research of the code, but it has happened already a few times. – Iiridayn Oct 02 '12 at 20:56
  • 9
    -1: This is pure opinion (so makes it generally a bad answer as this would be a reason to close-vote the question instead); but next to that, most likely not a thoughful one in the sense of programming. See http://programmers.stackexchange.com/q/89073/24482 – hakre May 18 '14 at 16:15
  • @hakre I see it backwards, the question is the one that (as it is currently stated) encourages opinion based answers, there is a flag for this – Purefan Jun 17 '17 at 22:55
15

The reason are:

  1. Declaring a class as final prevents it from being subclassed—period; it’s the end of the line.

  2. Declaring every method in a class as final allows the creation of subclasses, which have access to the parent class’s methods, but cannot override them. The subclasses can define additional methods of their own.

  3. The final keyword controls only the ability to override and should not be confused with the private visibility modifier. A private method cannot be accessed by any other class; a final one can.

—— quoted from page 68 of the book PHP Object-Oriented Solutions by David Powers.

For example:

final childClassname extends ParentsClassname {
    // class definition omitted
}

This covers the whole class, including all its methods and properties. Any attempt to create a child class from childClassname would now result in a fatal error. But,if you need to allow the class to be subclassed but prevent a particular method from being overridden, the final keyword goes in front of the method definition.

class childClassname extends parentClassname { 
    protected $numPages;

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

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

In this example, none of them will be able to overridden the PageCount() method.

Pang
  • 9,564
  • 146
  • 81
  • 122
li bing zhao
  • 1,388
  • 13
  • 12
6

A final class is one which cannot be extended http://php.net/manual/en/language.oop5.final.php

You would use it where the class contained methods which you specifically do not want overridden. This may be because doing do would break your application in some way.

Yousha Aleayoub
  • 4,532
  • 4
  • 53
  • 64
Matt Asbury
  • 5,644
  • 2
  • 21
  • 29
  • Sorry but that was not my question. – Inga Johansson Nov 22 '10 at 17:07
  • Sorry I got carried away with the submit button. Edited. Please let me know if you would like me to expand – Matt Asbury Nov 22 '10 at 17:09
  • 2
    Yes it was, "If I understand it correctly, 'final' **enables** it to extend 'Foo'." – Malfist Nov 22 '10 at 17:09
  • `You would use it where the class contained methods which you specifically do not want overridden. This may be because doing do would break your application in some way.` could you give an example? Instead of overriding, extending could also add functionality instead of overriding, or?? – Inga Johansson Nov 22 '10 at 17:10
  • Maybe you created a class to handle authentication. By definition this class must be secure. A class that extends this may contain methods that use properties from the parent class and uses them in an unsecure way thus making a system insecure. Making the authentication class final would prevent this. – Matt Asbury Nov 22 '10 at 17:15
  • 1
    @Gumbo, I just want to know if creating Final classes is a bad practice and the PHP manual ain't telling me that. Can you tell me where I can find that? – Inga Johansson Nov 22 '10 at 17:45
  • @Inga Johansson: I was rather addressing to @matt_asbury. – Gumbo Nov 22 '10 at 17:49
  • @Gumbo - You mean the link used. No problem. Edited. – Matt Asbury Nov 22 '10 at 20:05
5

My 2 cents:

When To Use final:

  • NEVER!!

Why?

  • it breaks the ability to use test doubles when unit testing
  • could lead to increased code duplication because of gaps in functionality in downstream code
  • the reasons to use it are all training issues being addressed with a radical shortcut

Bad Reasons to Use It:

  • Preventing massive inheritance chain of doom (training issue)
  • Encouraging composition (training issue)
  • Force the developer to think about user public API (training issue)
  • Force the developer to shrink an object's public API (training issue? code reviews?)
  • A final class can always be made extensible (relevance?)
  • extends breaks encapsulation (what? poor encapsulation breaks encapsulation; not inheritance. inheritance is not inherently evil.)
  • You don't need that flexibility (typical thinking behind short-sighted development. be prepared to hit a feature wall + training issue)
  • You are free to change the code (relevance?)
John Brown
  • 93
  • 1
  • 1
  • Could you explain what you mean by 'training issue' since this is your main argument agains the `final` keyword? – Danielle Suurlant Mar 30 '21 at 10:17
  • 5
    With respect, I disagree vehemently with this. First off, it's not a "training issue" - sometimes the people using your class simply aren't your responsibility, such as if you're writing a library, but you still want to stop them shooting themselves in the foot with inheritance. The mock issue can be overcome by having the class implement an interface and mocking that. If some of the functionality needs to be reused it can be extracted to a subclass or trait, and if you need to duplicate a significant amount of code to reimplement functionality the class was probably too big anyway. – Matthew Daly Apr 06 '21 at 20:33
  • 1
    Sorry, the refactoring is called Extract class, not extract subclass. – Matthew Daly Apr 06 '21 at 21:40
  • As for flexibility, that again often comes down to the class doing too much - if your implementation isn't flexible enough without being extended it's probably doing too much and you should consider refactoring some of the functionality out into separate classes. And for some changes in behaviour such as adding caching or logging, decorating the class is a better method that's not tied to that implementation and keeps the new functionality separate. – Matthew Daly Apr 06 '21 at 22:46
  • 2
    "training issue" means it's really not a coding problem, it's a people problem. talk to the people. document better. have frequent design discussions. – John Brown May 27 '21 at 00:06
  • "sometimes the people using the class simply aren't your responsibility" ... later on "you still want to stop them [from] shooting themselves in the foot with inheritance" make up your mind. are you trying to pigeon hole the code or not? if it's a library, let them do what they want. it's just a library. unit testing with interfaces? you use interfaces for your dependencies but your unit tests should test the actual code in the actual class. otherwise you aren't unit testing. – John Brown May 27 '21 at 00:12
  • correction on the unit tests thing: yes you can use the interface when the class that has final members is not the class under test. but what if you do what a variant of the class that actually adds or modifies some aspect of is behavior for a certain type or implementation? then you have to re-write an entire class just to add a little something different or extra. why? just why? – John Brown May 27 '21 at 00:22
  • @JohnBrown If you're not someone's line manager or a member of the same development team, you aren't responsible for their training and personal development as coders, and likely can have little influence on that. But even if our only interaction is in regards to, say, a library I wrote and put on Github that you're using, I have a vested interest in making sure people use it in a way I'd consider safe. If you go and extend it and report a bug that turns out to be in a class that extends mine, that's going to be a waste of my time to deal with – Matthew Daly Jul 06 '21 at 08:45
  • @JohnBrown And I can fill my documentation with notes about "This class isn't meant to be extended. Don't extend it", but I've still got no guarantees. But if I add one single `final` keyword I have a cast-iron guarantee that it's impossible to extend, and I don't need to think about it any more. If someone needs to add functionality they can do so the correct way, through composition. – Matthew Daly Jul 06 '21 at 08:48
  • @JohnBrown As for the issue about a variant of the class, you have a number of options. For instance, suppose you had a library that dealt with sending emails, some via REST and some via SOAP. You could extract the part that deals with sending the actual request to two Transport subclasses, one for REST and one for SOAP, and use them in your variant classes. Or you could extract that functionality to a trait. – Matthew Daly Jul 06 '21 at 08:57
  • @JohnBrown Yes, there are some occasional cases where it does mean you do wind up duplicating code a little, but if you're doing a good job of extracting things to subclasses it's pretty rare anyway. A handful of lines aren't that big a deal. – Matthew Daly Jul 06 '21 at 09:00
  • 2
    Completely agree with this answer. I'm tired of seeing the `final` keyword on every class in a php project. Seems some devs are even proud of saying that in their IDE they have the `final` keyword in their class template file. This is horrible. C++ also received the `final` keyword and you have videos already talking about how you should be extremely careful when using it. – AntonioCS Nov 16 '21 at 17:14
  • I'd also add this it's not entirely impossible to mock classes marked as final - the package `dg/bypass-finals` makes this possible. But a well-designed application should be dependent only on interfaces, not concrete classes. – Matthew Daly Jul 11 '22 at 09:56
  • 3
    So, this is an old thread now. In addition to all other points made above, the Final keyword is just fundamentally too much hubris for me to adopt. I cannot assume that any 1 approach to a software problem is the only and best approach ever. This is a journey of perpetual learning. Therefore, whenever I write code, I want to make life easier, not harder for the next designer to do whatever they want/need to extend & test functionality for their project. I won't be using Final unless I'm on a client's project where I have direct orders to do so. I said what I said. – John Brown Jul 12 '22 at 13:06
  • 1
    @JohnBrown Using `final` is not an act of hubris, and it doesn't "crystallise" your code as being the best approach ever. All it is saying is "This class is not designed to be extended". Designing a class to be extended is a *lot* more work than designing one that isn't, and if you go and extend a class that's not explicitly designed to be extended, you're *extremely* likely to end up shooting yourself in the foot. Increasingly I'm of the opinion that inheritance is only a fringe benefit of OOP and should have less emphasis - OOP is more about interaction between objects than inheritance. – Matthew Daly Aug 02 '22 at 09:49
  • 1
    @JohnBrown As long as you depend on interfaces, not concrete classes, mocking isn't an issue, and you can extend functionality without inheritance by using the [decorator pattern](https://refactoring.guru/design-patterns/decorator/php/example#example-1), which is a much more elegant and cleaner method in many cases. – Matthew Daly Aug 02 '22 at 09:50
  • 1
    @JohnBrown Extending classes that aren't explicitly intended to be extended can also be a minefield of bugs. The internal API may not be kept consistent, so it may break any time you run `composer update`. The decorator pattern is often a safer alternative because it depends on a defined interface, so as long as that interface remains consistent, it should be fairly safe. – Matthew Daly Aug 02 '22 at 09:56
  • 1
    @JohnBrown Plus there are many classes that by definition you will almost never want to extend. Controllers and models will often fall into that category, and where they are intended to be extended (such as a generic "resource" controller for an API), they often represent abstract versions of those items, in which case they should be declared as `abstract` to make this explicit. Likewise, I can't think of any circumstances under which a database migration class would ever need to be extended. – Matthew Daly Aug 02 '22 at 10:05
  • 1
    @JohnBrown For other purposes, as long as a class implements a given interface, that interface covers the entire public API of that class, and the things that depend on that class are dependent only on the interface, then I would always make that class final, because it's easy to replace with any other implementation, and we can change the functionality without changing the class by using a decorator. – Matthew Daly Aug 02 '22 at 10:15
  • Okay. I'm still not convinced. You are free to have whatever opinion you want. – John Brown Aug 10 '22 at 00:04