|Matt Zadstra's book, PHP Objects, Patterns and Practice, aims to give an overview of sound OOP design in PHP applications, with a direct focus on Design Patterns. Until PHP5, OOP was not really possible with the language. Object and class support was sketchy, in many ways little more than a clumsy afterthought. Even now, the OOP mechanisms that exist are not complete, however they are at last adequate for the implementation of an entirely OOP design.
When starting the design process for new software, we usually start with a requirements analysis, where we examine what the system must achieve, what its scope will be (the domain it will operate on), and what its outputs should be.
In an OO system, we have a structure that lends itself to atomicy, encouraging us to divide and conquer our problem. We think about the data domain each object must work on, which often guides us when defining the object properties, and we focus on how our classes interact externally, which will often have some correspondence with the methods we finally implement.
The external interactions are our focus at this early stage, as opposed to the internal implementation which we worry about later. We can boil down these interactions into a defined interface that each class must conform to.
The interface defines a type, a class, and may itself use other types defined elsewhere.
We can also use inheritance where classes share qualities or behaviours to enhance the maintainability of our design.
In addition to these, there are many different types of relationship that we might define for our classes during the design process. A particular class might be composed of other classes or might manage a collection of another class. (see pp 98)
With OOP, we can break away from the rigid top-down, sequential control flow of yore and embrace more distributed organic arrangements.
In OOP, we shouldn't get too hung up on a direct correspondence between objects in our system and the real world objects our system must deal with. While this often has some validity, and certainly can be a useful starting point, it can lead to clumsy bloated code as we try to make each object deal with everything required by its real-world counterpart.
For instance we may try to shoe-horn functionality for accessing a supplier's web service into a Product class that is already dealing with tracking inventory.
A better approach is to be clear on a class's primary function and to ensure it stays focussed on that. One rule of thumb is to keep your description of the class less than 25 words, avoid the use of 'and' or 'or'. If this becomes difficult, it's probably time to split functionality out into more classes.
Coupling is used when discussing how intertwined elements of a system are with other elements. In a highly coupled system, changes in one area will frequently lead to changes in many other areas, scattered around the system as a whole.
A system with high cohesion is one where logically related functionality is physically grouped together. In OOP this generally means each class defies all the operations with clearly related logic.
A well designed OOP system tightly defines the responsibility of all the components (ie classes) in a system and each component is logically independent of the system as a whole. This principle, of loose coupling and high cohesion, is termed 'orthogonality'.
Orthogonality is good, because it facilitates re-use without the need for refactoring the code. It also makes maintenance safer, because changes are localised to the components directly affected.
This localisation also serves to make the system more robust, as bugs should be limited in scope. How useful this is in practice is arguable however, as in certain cases at least, this property will tend to conceal bugs that would have been more obvious in a procedural system.
Polymorphism is not just a silly word, it's also a cool and powerful tool in the OOP developer's workshop.
The principle is that a single interface is implemented by a whole set of classes.
This enables the whole family of classes to be handled by the same code - for instance, all can be accepted as an argument to a single method. (p104, and p129 ch8)
The Design Patterns
The principle of the Design Pattern is borrowed form the world of architecture, where they first appeared in the 70s.
The basic idea is that there are recurring themes which resurface in the solutions to many different problems, and these can be abstracted out to make them easier to apply by identifying their essential features. These recurring themes are formalised into the Design Patterns, and the concept was famously applied to the domain of computing problems by the Gang of Four.
Zadstra's book groups the patterns it looks at into 5 broad categories.
Patterns that Generate Objects
Patterns that Organise Objects
In the most general sense, Composition describes a data type that contains (ie is composed of) other data types. Classes themselves are examples of composition as they are usually made up of member variables of varying types. Object Composition is where objects contain instances of other objects, typically as private instance variables. It is often contrasted with inheritance, and is generally considered a preferable method of object organisation.
Template View and View Helper
Unit of Work
Domain Object factory
Selection Factory and Update Factory
Overall this is a good book that really gets you thinking about how you approach coding problems. It's well written and accessible, Zadstra comes across as an authoritative yet approachable author and he presents many ideas without waffle.
PHP Objects, Patterns and Practice, by Matt Zadstra, 2010, published by Apress.