CHAPTER 6 ■ OBJECTS AND DESIGN
It is important to note that polymorphism doesn’t banish conditionals. Methods like
ParamHandler::getInstance() will often determine which objects to return based on switch or if
statements. These tend to centralize the conditional code into one place, though.
As you have seen, PHP enforces the interfaces defined by abstract classes. This is useful because we
can be sure that a concrete child class will support exactly the same method signatures as those defined
by an abstract parent. This includes all class type hints and access controls. Client code can, therefore,
treat all children of a common superclass interchangeably (as long it only relies on only functionality
defined in the parent). There is an important exception to this rule: there is no way of constraining the
return type of a method.
■Note At the time of this writing, there are plans to incorporate return type hinting in a future release of PHP.
Whether this will happen, though, is by no means certain.
The fact that you cannot specify return types means that it is possible for methods in different
subclasses to return different class types or primitives. This can undermine the interchangeability of
types. You should try to be consistent with your return values. Some methods may be defined to take
advantage of PHP’s loose typing and return different types according to circumstances. Other methods
enter into an implicit contract with client code, effectively promising that they will return a particular
type. If this contract is laid down in an abstract superclass, it should be honored by its concrete children
so that clients can be sure of consistent behavior. If you commit to return an object of a particular type,
you can, of course, return an instance of a subtype. Although the interpreter does not enforce return
types, you can make it a convention in your projects that certain methods will behave consistently. Use
comments in the source code to specify a method’s return type.
Encapsulation
Encapsulation simply means the hiding of data and functionality from a client. And once again, it is a
key object-oriented concept.
On the simplest level, you encapsulate data by declaring properties private or protected. By hiding
a property from client code, you enforce an interface and prevent the accidental corruption of an
object’s data.
Polymorphism illustrates another kind of encapsulation. By placing different implementations
behind a common interface, you hide these underlying strategies from the client. This means that any
changes that are made behind this interface are transparent to the wider system. You can add new
classes or change the code in a class without causing errors. The interface is what matters, and not the
mechanisms working beneath it. The more independent these mechanisms are kept, the less chance
that changes or repairs will have a knock-on effect in your projects.
Encapsulation is, in some ways, the key to object-oriented programming. Your objective should be
to make each part as independent as possible from its peers. Classes and methods should receive as
much information as is necessary to perform their allotted tasks, which should be limited in scope and
clearly identified.
The introduction of the private, protected, and public keywords have made encapsulation easier.
Encapsulation is also a state of mind, though. PHP 4 provided no formal support for hiding data. Privacy
had to be signaled using documentation and naming conventions. An underscore, for example, is a
common way of signaling a private property: