Objects were not always a key part of the PHP project. In fact, they were once described as an afterthought by PHP’s designers.
As afterthoughts go, this one has proved remarkably resilient. In this chapter, I introduce this book’s coverage of objects by summarizing the development of PHP’s object-oriented features.
We will look at the following:
- PHP/FI 2.0: PHP, but not as we know it.
- PHP 3: Objects make their first appearance.
- PHP 4: Object-oriented programming grows up.
- PHP 5: Objects at the heart of the language.
- PHP 7: Closing the gap.
- PHP 8: The consolidation continues.
The Accidental Success of PHP Objects
With PHP’s extensive object support and so many object-oriented PHP libraries and applications in circulation, the rise of the object in PHP may seem like the culmination of a natural and inevitable process. In fact, nothing could be further from the truth.
In the Beginning: PHP/FI
The genesis of PHP as we know it today lies with two tools developed by Rasmus Lerdorf using Perl. PHP stood for Personal Home Page Tools. FI stood for Form Interpreter. Together, they comprised macros for sending SQL statements to databases, processing forms, and flow control.
These tools were rewritten in C and combined under the name PHP/FI 2.0. The language at this stage looked different from the syntax we recognize today, but not that different. There was support for variables, associative arrays, and functions. Objects, however, were not even on the horizon.
Syntactic Sugar: PHP 3
In fact, even as PHP 3 was in the planning stage, objects were off the agenda. The principal architects of PHP 3 were Zeev Suraski and Andi Gutmans. PHP 3 was a complete rewrite of PHP/FI 2.0, but objects were not deemed a necessary part of the new syntax.
According to Zeev Suraski, support for classes was added almost as an afterthought (on August 27, 1997, to be precise). Classes and objects were actually just another way to define and access associative arrays.
Of course, the addition of methods and inheritance made classes much more than glorified associative arrays, but there were still severe limitations on what you might do with your classes. In particular, you could not access a parent class’s overridden methods (don’t worry if you don’t know what this means yet; I will explain later). Another disadvantage that I will examine in the next section was the less than optimal way that objects were passed around in PHP scripts.
That objects were a marginal issue at this time is underlined by their lack of prominence in official documentation. The manual devoted one sentence and a code example to objects. The example did not illustrate inheritance or properties.
PHP 4 and the Quiet Revolution
If PHP 4 was yet another groundbreaking step for the language, most of the core changes took place beneath the surface. The Zend Engine (its name derived from Zeev and Andi) was written from scratch to power the language. The Zend Engine is one of the main components that drive PHP. Any PHP function you might care to call is in fact part of the high-level extension layer. These do the busywork they were named for, like talking to database APIs or juggling strings for you. Beneath that, the Zend Engine manages memory, delegates control to other components, and translates the familiar PHP syntax you work with every day into runnable bytecode. It is the Zend Engine that we have to thank for core language features like classes.
From our objective perspective, the fact that PHP 4 made it possible to override parent methods and access them from child classes was a major benefit.
A major drawback remained, however. Assigning an object to a variable, passing it to a function, or returning it from a method resulted in a copy being made. Consider an assignment like this:
$my_obj = new User('bob');
$other = $my_obj;
This resulted in the existence of two User objects rather than two references to the same User object. In most object-oriented languages, you would expect assignment by reference rather than by value. This means that you would pass and assign handles that point to objects rather than copy the objects themselves. The default pass-by-value behavior resulted in many obscure bugs as programmers unwittingly modified objects in one part of a script, expecting the changes to be seen via references elsewhere. Throughout this book, you will see many examples in which I maintain multiple references to the same object.
Luckily, there was a way of enforcing pass by reference, but it meant remembering to use a clumsy construction.
Here’s how you would assign by reference:
$other =& $my_obj;
// $other and $my_obj point to same object
This enforces pass by reference:
function setSchool(&$school) {
// $school is now a reference to, not a copy of, passed object
}
And here is return by reference:
function &getSchool() {
// returning a reference, not a copy
return $this->school;
}
Although this worked fine, it was easy to forget to add the ampersand, and that meant it was all too easy for bugs to creep into object-oriented code. These were particularly hard to track down because they rarely caused any reported errors, just plausible but broken behavior.
Coverage of syntax in general and objects in particular was extended in the PHP manual and object-oriented coding began to bubble up to the mainstream. Objects in PHP were not uncontroversial (then as now, no doubt) and threads like “Do I need objects?” were common flame-bait in mailing lists. Indeed, the Zend site played host to articles that encouraged object-oriented programming side by side with others that sounded a warning note. Pass-by-reference issues and controversy notwithstanding, many coders just got on and peppered their code with ampersand characters. Object-oriented PHP grew in popularity. Zeev Suraski wrote this in an article for DevX.com:
“One of the biggest twists in PHP’s history was that despite the very limited functionality and despite a host of problems and limitations, object-oriented programming in PHP thrived and became the most popular paradigm for the growing numbers of off-the-shelf PHP applications. This trend, which was mostly unexpected, caught PHP in a suboptimal situation. It became apparent that objects were not behaving like objects in other OO languages and were instead behaving like [associative] arrays.”
As noted in the previous chapter, interest in object-oriented design became obvious in sites and articles online. PHP’s official software repository PEAR itself embraced object-oriented programming. With hindsight, it’s easy to think of PHP’s adoption of object-oriented support as a reluctant capitulation to an inevitable force. It’s important to remember that although object-oriented programming has been around since the 1960s, it really gained ground in the mid-1990s. Java, the great popularizer, was not released until 1995. A superset of C, a procedural language, C++ has been around since 1979. After a long evolution, it arguably made the leap to the big time during the 1990s. Perl 5 was released in 1994, another revolution within a formerly procedural language that made it possible for its users to think in objects (although some argue that Perl’s object-oriented support also felt like something of an afterthought). For a small procedural language, PHP developed its object support remarkably fast, showing a real responsiveness to the requirements of its users.
Change Embraced: PHP 5
PHP 5 represented an explicit endorsement of objects and object-oriented programming. That is not to say that objects were the only way to work with PHP (this book does not say that either, by the way). Objects were, however, recognized as a powerful and important means for developing enterprise systems, and PHP fully supported them in its core design.
Arguably one significant effect of the enhancements in PHP 5 was the adoption of the language by larger Internet companies. Both Yahoo! and Facebook, for example, started using PHP extensively within their platforms. With version 5, PHP became one of the standard languages for development and enterprise on the Internet.
Objects had moved from afterthought to language driver. Perhaps the most important change was the new apparent pass-by-reference behavior which replaced the evils of object copying. That was only the beginning, however. Throughout this book and particularly in this part of it, we will encounter many more enhancements including private and protected methods and properties, the static keyword, namespaces, type hints (now called type declarations), and exceptions. PHP 5 was around for a long time (about 12 years), and important new features were released incrementally.
Note: It is worth noting that PHP did not strictly speaking move to pass by reference with the introduction of PHP 5 and this has not changed. Instead, by default, when an object is assigned, passed to a method, or returned from one, an identifier to that object is copied. So unless you pin matters down and enforce pass by reference with the ampersand character, you are still performing a copy operation. In practical terms, however, there is usually little difference between this kind of copying and pass by reference since you reference the same target object with your copied identifier as you did with your original.
PHP 5.3, for example, brought namespaces. These let you create a named scope for classes and functions so that you are less likely to run into duplicate names as you include libraries and expand your system. They also rescue you from ugly but necessary naming conventions such as this:
class megaquiz_util_Conf {
}
Class names such as this are one way of preventing clashes between packages, but they can make for tortuous code.
We have also seen support for closures, generators, traits, and late static bindings.
PHP 7: Closing the Gap
Programmers are a demanding lot. For many lovers of design patterns, there were two key features that PHP still lacked. These were scalar type declarations and enforced return types. With PHP 5, it was possible to enforce the type of an argument passed to a function or method so long as you only needed to require an object, an array, or later callable code. Scalar values (like integers, strings, and floats) could not be enforced at all. Furthermore, if you wanted to declare a method or a function’s return type, you were altogether out of luck.
As you will see, object-oriented design often uses a method declaration as a kind of contract. The method demands certain inputs and reciprocally, it promises to give you a particular type of data back. PHP 5 programmers were forced to rely on comments, convention, and manual type checking to maintain contracts of this kind in many cases. Developers and commentators often complained about this. Here is a quote from the Fourth Edition of this book:
“there is still no commitment to provide support for hinted return types. This would allow you to declare in a method or function’s declaration the object type that it returns. This would then be enforced by the PHP engine. Hinted return types would further improve PHP’s support for pattern principles (principles such as “code to an interface, not an implementation”). I hope one day to revise this book to cover that feature!”
I’m pleased to write that the day did arrive! PHP 7 introduced scalar type declarations (previously known as type hints) and return type declarations. What’s more, PHP 7.4 took type safety even further by introducing typed properties. Naturally, all of that is covered in this edition.
PHP 7 also provided other nice-to-haves including anonymous classes and some namespace enhancements.
PHP 8: The Consolidation Continues
PHP has always been a great magpie, borrowing shiny proven features from other languages. PHP 8 introduces many new features including attributes (often known in other languages as annotations). These handy tags can be used to provide additional contextual information about classes, methods, properties, and constants in a system. Furthermore, PHP 8 has continued to extend its support for type declarations. Particularly interesting in this area is the union type declaration. This allows you to declare that the type of a property or parameter should be constrained to one of several specified types. You can lock down your types at the same time as taking advantage of PHP’s type flexibility. The very definition of having your cake and eating it!
Advocacy and Agnosticism: The Object Debate
Objects and object-oriented design seem to stir passions on both sides of the enthusiasm divide. Many excellent programmers have produced excellent code for years without using objects, and PHP continues to be a superb platform for procedural web programming.
This book naturally displays an object-oriented bias throughout, a bias that reflects my object-infected outlook. Because this book is a celebration of objects and an introduction to object-oriented design, it is inevitable that the emphasis is unashamedly object-oriented. Nothing in this book is intended, however, to suggest that objects are the one true path to coding success with PHP.
Whether a developer chose to work with PHP as an object-oriented language was once a matter of preference. This is still true to the extent that one can create perfectly acceptable working systems using functions and global code. Some great tools (e.g., WordPress) are still procedural in their underlying architecture (though even these may make extensive use of objects these days). It is, however, becoming increasingly hard to work as a PHP programmer without using and understanding PHP’s support for objects, not least because the third-party libraries you are likely to rely upon in your projects will themselves likely be object-oriented.
Still, as you read, it is worth bearing in mind the famous Perl motto “There’s more than one way to do it.” This is especially true of smaller scripts where quickly getting a working example up and running is more important than building a structure that will scale well into a larger system (scratch projects of this sort are often known as “spikes”).
Code is a flexible medium. The trick is to know when your quick proof of concept is becoming the root of a larger development and to call a halt before lasting design decisions are made for you by the sheer weight of your code. Now that you have decided to take a design-oriented approach to your growing project, I hope that this book provides the help that you need to get started building object-oriented architectures.
Summary
This short chapter placed objects in their context in the PHP language. The future for PHP is very much bound up with object-oriented design. In the next few chapters, I take a snapshot of PHP’s current support for object features and introduce some design issues.