Final, abstract and other cousins
Counting classes in an application
How many classes are there in a PHP application? A simple count based on the class
keyword gives a quick answer. Modern PHP application range from a dozen of units to a dozen of thousands.
Yet, each class
keyword doesn’t produce a concrete class. Inheritance must be accounted for : inheritance merges several classes into one. The last child class is build on top of all the parent ones. That way, they act as one class only.
On the other hand, the parent classes may have a life of their own. Even as a partial class, it is possible to instantiate them. This is where the final
and abstract
keywords come into play.
Let’s review these features, and decide when to apply them.
Abstract, final and concrete classes
concrete classes
The most common type of class is the concrete class. Concrete classes are classes that are instantiated in the code. Then, such objects are processed by the application. Without any other coding option, classes are concrete classes.
abstract classes
The direct opposite of concrete classes are the abstract
ones. Those must bear the abstract
keyword. With it, PHP will prevent any instantiation. An abstract
class must be inherited, and, when the child class doesn’t have the abstract
keyword too, this might instantiated.
<?php abstract class Pot {} class Vase extends Pot {} $object = new Vase(); ?>
Two side notes on abstract
:
- It also applies to methods. An abstract method must be in an abstract class. The contrary doesn’t apply : an abstract class doesn’t need to have an abstract method.
- An abstract class may have abstract or concrete child, and vice versa : a concrete class may be the parent of an abstract class. This last class will need to be inherited yet again before being instantiated. Very unusual piece of code.
abstract
classes are often presented as class templates. They design a number of constraints on the child classes, and enforce methods onto them. This is the conception approach, where templates are decided before coding. In this article, we review code, and figure out which could be abstract
. That will cast a different light on the code.
final classes
final
is rather on the opposite end of the spectrum to abstract
. It prevents a class to be extended again. This means that afinal
class is almost surely a concrete class : it cannot be inherited again, so its features must be accessible, via an object.
In fact, it is not possible to make a class that is both abstract
and final
: PHP complains at compilation time that Cannot use the final modifier on an abstract class
. In practice, a single abstract
class, or a class without option and never instantiated are possible : this is the case of static classes, gathering common tools as static methods. We’ll leave them out of this article.
Who’s final and who’s abstract?
Let’s review the possibilites, depending on the number of classes in a family.
One class
One may to use final and abstract with one class[/caption]
Let’s start with a single class. Then, only the final
keyword is possible.
If we set aside considerations outside the scope of the code itself, then the class should be final
. final
keyword should actually be the default for such classes, until the need to extend them appears.
Two classes
With two classes, it is now possible to use abstract
. Possible, and not compulsory : so the parent class may or may not be abstract
. The parent cannot be final
because, obviously, there wouldn’t be any child class.
By default, the parent class should bear the abstract
option. After all, it is a partial class to the child one. Unless there is an instantiation, it is safe to do so.
Three classes (or more)
With three classes, the class family grows, and a certain pattern emerges : the abstract
classes are at the top, if any, and the final
class at the bottom.
The lazy way is to leave out all the options, and keep them all unmarked.
How Abstract is a family ?
The abstract
classes are not instantiated. So are non-instantiated parent classes supposed to be abstract
?
This is a tricky question : the intermediate classes are created to group certain methods or certains meaning within the class family. In the end of the development, if they are not instantiated, they shall as well be marked as abstract
.
Indeed, it is easy to convert a child class to a parent class, since the classes are different aspects of the same object. In the example above, a Vase
is also a Pot
. That translation happens automatically with typehinting, for example.
On the other hand, the contrary is not possible : a Pot
is not a Vase
, and there are no easy way to convert a general class into a specific class. So, as soon as the class is a parent class, and non instantiated, it should be marked as abstract
.
Reviewing a class family for final
and abstract
Here are a few questions to ask when reviewing a class family :
- Is the class a parent and it is never instantiated? Then, it could be
abstract
. See Class could be abstract - Is the class the last in a family branch ? It could be
final
. See Class could be final
The simplistic approach is to make all parent abstract
and only the last children final
. That way, any partial usage of the classes can be reviewed when the time comes to start using them independantly.
Until then, happy auditing!