Discover millions of ebooks, audiobooks, and so much more with a free trial

Only $11.99/month after trial. Cancel anytime.

PHP 8 Objects, Patterns, and Practice: Mastering OO Enhancements, Design Patterns, and Essential Development Tools
PHP 8 Objects, Patterns, and Practice: Mastering OO Enhancements, Design Patterns, and Essential Development Tools
PHP 8 Objects, Patterns, and Practice: Mastering OO Enhancements, Design Patterns, and Essential Development Tools
Ebook1,152 pages9 hours

PHP 8 Objects, Patterns, and Practice: Mastering OO Enhancements, Design Patterns, and Essential Development Tools

Rating: 0 out of 5 stars

()

Read preview

About this ebook

Learn how to develop elegant and rock-solid systems using PHP, aided by three key elements: object fundamentals, design principles, and best practices. The 6th edition of this popular book has been fully updated for PHP 8, including attributes, constructor property promotion, new argument and return pseudo-types, and more. It also covers many features new since the last edition including typed properties, the null coalescing operator, and void return types. This book provides a solid grounding in PHP's support for objects, it builds on this foundation to instill core principles of software design and then covers the tools and practices needed to develop, test, and deploy robust code.

PHP 8 Objects, Patterns, and Practice begins by covering PHP's object-oriented features. It introduces key topics including class declarations, inheritance, and reflection. The next section is devoted to design patterns. It explains the principles that make patterns powerful. You’ll cover many of the classic design patterns including enterprise and database patterns. The last segment of the book covers the tools and practices that can help turn great code into a successful project. The section shows how to manage multiple developers and releases with git, and how to manage builds and dependencies with Composer. It also explores strategies for automated testing and continuous integration.

After reading and using this book, you will have mastered object-oriented enhancements, design patterns, and the essential development tools available for PHP 8. 

What You Will Learn

  • Work with object fundamentals: write classes and methods, instantiate objects, and create powerful class hierarchies using inheritance
  • Master advanced object-oriented features, including static methods and properties, managing error conditions with exceptions, and creating abstract classes and interfaces
  • Understand and use design principles to deploy objects and classes effectively in your projects
  • Discover a set of powerful patterns that you can implement in your own projects
  • Guarantee a successful project including unit testing; version control and build, installation, and package management; and continuous integration

Who This Book Is For

Anyone with at least a basic knowledge of PHP who wants to use its object-oriented features in their projects. It is also for PHP coders who want to learn about the practices and tools (version control, testing, continuous integration, etc) that can make projects safe, elegant and stable.

LanguageEnglish
PublisherApress
Release dateApr 2, 2021
ISBN9781484267912
PHP 8 Objects, Patterns, and Practice: Mastering OO Enhancements, Design Patterns, and Essential Development Tools

Related to PHP 8 Objects, Patterns, and Practice

Related ebooks

Internet & Web For You

View More

Related articles

Reviews for PHP 8 Objects, Patterns, and Practice

Rating: 0 out of 5 stars
0 ratings

0 ratings0 reviews

What did you think?

Tap to rate

Review must be at least 10 words

    Book preview

    PHP 8 Objects, Patterns, and Practice - Matt Zandstra

    Part IObjects

    © Matt Zandstra 2021

    M. ZandstraPHP 8 Objects, Patterns, and Practicehttps://doi.org/10.1007/978-1-4842-6791-2_1

    1. PHP: Design and Management

    Matt Zandstra¹  

    (1)

    Brighton, UK

    In July 2004, PHP 5.0 was released. This version introduced a suite of radical enhancements. Perhaps first among these was radically improved support for object-oriented programming. This stimulated much interest in objects and design within the PHP community. In fact, this was an intensification of a process that began when version 4 first made object-oriented programming with PHP a serious reality.

    In this chapter, I look at some of the needs that coding with objects can address. I very briefly summarize some aspects of the evolution of patterns and related practices.

    I also outline the topics covered by this book. I will look at the following:

    The evolution of disaster: A project goes bad

    Design and PHP: How object-oriented design techniques took root in the PHP community

    This book: Objects, Patterns, Practice

    The Problem

    The problem is that PHP is just too easy. It tempts you to try out your ideas and flatters you with good results. You write much of your code straight into your web pages, because PHP is designed to support that. You add utility functions (such as database access code) to files that can be included from page to page, and before you know it, you have a working web application.

    You are well on the road to ruin. You don’t realize this, of course, because your site looks fantastic. It performs well, your clients are happy, and your users are spending money.

    Trouble strikes when you go back to the code to begin a new phase. Now you have a larger team, some more users, and a bigger budget. Yet, without warning, things begin to go wrong. It’s as if your project has been poisoned.

    Your new programmer is struggling to understand code that is second nature to you, although perhaps a little byzantine in its twists and turns. She is taking longer than you expected to reach full strength as a team member.

    A simple change, estimated at a day, takes three days when you discover that you must update 20 or more web pages as a result.

    One of your coders saves his version of a file over major changes you made to the same code some time earlier. The loss is not discovered for three days, by which time you have amended your own local copy. It takes a day to sort out the mess, holding up a third developer who was also working on the file.

    Because of the application’s popularity, you need to shift the code to a new server. The project has to be installed by hand, and you discover that file paths, database names, and passwords are hard-coded into many source files. You halt work during the move because you don’t want to overwrite the configuration changes the migration requires. The estimated two hours becomes eight as it is revealed that someone did something clever involving the Apache module ModRewrite, and the application now requires this to operate properly.

    You finally launch phase 2. All is well for a day and a half. The first bug report comes in as you are about to leave the office. The client phones minutes later to complain. Her report is similar to the first, but a little more scrutiny reveals that it is a different bug causing similar behavior. You remember the simple change back at the start of the phase that necessitated extensive modifications throughout the rest of the project.

    You realize that not all of the required modifications are in place. This is either because they were omitted to start with or because the files in question were overwritten in merge collisions. You hurriedly make the modifications needed to fix the bugs. You’re in too much of a hurry to test the changes, but they are a simple matter of copy and paste, so what can go wrong?

    The next morning, you arrive at the office to find that a shopping basket module has been down all night. The last-minute changes you made omitted a leading quotation mark, rendering the code unusable. Of course, while you were asleep, potential customers in other time zones were wide awake and ready to spend money at your store. You fix the problem, mollify the client, and gather the team for another day’s firefighting.

    This everyday tale of coding folk may seem a little over the top, but I have seen all these things happen over and over again. Many PHP projects start their life small and evolve into monsters.

    Because the presentation layer also contains application logic, duplication creeps in early as database queries, authentication checks, form processing, and more are copied from page to page. Every time a change is required to one of these blocks of code, it must be made everywhere that the code is found, or bugs will surely follow.

    Lack of documentation makes the code hard to read, and lack of testing allows obscure bugs to go undiscovered until deployment. The changing nature of a client’s business often means that code evolves away from its original purpose until it is performing tasks for which it is fundamentally unsuited. Because such code has often evolved as a seething, intermingled lump, it is hard, if not impossible, to switch out and rewrite parts of it to suit the new purpose.

    Now, none of this is bad news if you are a freelance PHP consultant. Assessing and fixing a system like this can fund expensive espresso drinks and DVD box sets for six months or more. More seriously, though, problems of this sort can mean the difference between a business’s success and failure.

    PHP and Other Languages

    PHP’s phenomenal popularity meant that its boundaries were tested early and hard. As you will see in the next chapter, PHP started life as a set of macros for managing personal home pages. With the advent of PHP 3 and, to a greater extent, PHP 4, the language rapidly became the successful power behind large enterprise websites. In many ways, however, the legacy of PHP’s beginnings carried through into script design and project management. In some quarters, PHP retained an unfair reputation as a hobbyist language, best suited for presentation tasks.

    About this time (around the turn of the millennium), new ideas were gaining currency in other coding communities. An interest in object-oriented design galvanized the Java community. Since Java is an object-oriented language, you may think that this is a redundancy. Java provides a grain that is easier to work with than against, of course, but using classes and objects does not in itself determine a particular design approach.

    The concept of the design pattern as a way of describing a problem, together with the essence of its solution, was first discussed in the 1970s. Perhaps aptly, the idea originated in the field of architecture, not computer science, in a seminal work by Christopher Alexander: A Pattern Language (Oxford University Press, 1977). By the early 1990s, object-oriented programmers were using the same technique to name and describe problems of software design. The seminal book on design patterns, Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional, 1995), by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (henceforth referred to in this book by their affectionate nickname, the Gang of Four), is still indispensable today. The patterns it contains are a required first step for anyone starting out in this field, which is why most of the patterns in this book are drawn from it.

    The Java language itself deployed many core patterns in its API, but it wasn’t until the late 1990s that design patterns seeped into the consciousness of the coding community at large. Patterns quickly infected the computer sections of Main Street bookstores, and the first flame wars began on mailing lists and in forums.

    Whether you think that patterns are a powerful way of communicating craft knowledge or largely hot air (and, given the title of this book, you can probably guess where I stand on that issue), it is hard to deny that the emphasis on software design they have encouraged is beneficial in itself.

    Related topics also grew in prominence. Among them was Extreme Programming (XP), championed by Kent Beck. XP is an approach to projects that encourages flexible, design-oriented, highly focused planning and execution.

    Prominent among XP’s principles is an insistence that testing is crucial to a project’s success. Tests should be automated, run often, and preferably designed before their target code is written.

    XP also dictates that projects should be broken down into small (very small) iterations. Both code and requirements should be scrutinized at all times. Architecture and design should be a shared and constant issue, leading to the frequent revision of code.

    If XP was the militant wing of the design movement, then the moderate tendency is well represented by one of the best books about programming that I have ever read: The Pragmatic Programmer: From Journeyman to Master by Andrew Hunt and David Thomas (Addison-Wesley Professional, 1999).

    XP was deemed a tad cultish by some, but it grew out of two decades of object-oriented practice at the highest level, and its principles were widely cannibalized. In particular, code revision, known as refactoring, was taken up as a powerful adjunct to patterns. Refactoring has evolved since the 1980s, but it was codified in Martin Fowler’s catalog of refactorings, Refactoring: Improving the Design of Existing Code (Addison-Wesley Professional), which was published in 1999 and defined the field.

    Testing, too, became a hot issue with the rise to prominence of XP and patterns. The importance of automated tests was further underlined by the release of the powerful JUnit test platform, which became a key weapon in the Java programmer’s armory. A landmark article on the subject, Test Infected: Programmers Love Writing Tests by Kent Beck and Erich Gamma (http://junit.sourceforge.net/doc/testinfected/testing.htm), gives an excellent introduction to the topic and remains hugely influential.

    PHP 4 was released at about this time, bringing with it improvements in efficiency and, crucially, enhanced support for objects. These enhancements made fully object-oriented projects a possibility. Programmers embraced this feature, somewhat to the surprise of Zend founders Zeev Suraski and Andi Gutmans, who had joined Rasmus Lerdorf to manage PHP development. As you shall see in the next chapter, PHP’s object support was by no means perfect. But with discipline and careful use of syntax, one could really begin to think in objects and PHP at the same time.

    Nevertheless, design disasters such as the one depicted at the start of this chapter remained common. Design culture was some way off and almost nonexistent in books about PHP. Online, however, the interest was clear. Leon Atkinson wrote a piece about PHP and patterns for Zend in 2001, and Harry Fuecks launched his journal at www.phppatterns.com (now defunct) in 2002. Pattern-based framework projects such as BinaryCloud began to emerge, as well as tools for automated testing and documentation.

    The release of the first PHP 5 beta in 2003 ensured the future of PHP as a language for object-oriented programming. Zend Engine 2 provided greatly improved object support. Equally important, it sent a signal that objects and object-oriented design were now central to the PHP project.

    Over the years, PHP 5 continued to evolve and improve, incorporating important new features such as namespaces and closures. During this time, it secured its reputation as the best choice for server-side web programming.

    PHP 7, released in December 2015, represented a continuation of this trend. In particular, it provided support for both parameter and return type declarations—two features that many developers (together with previous editions of this book) had been clamoring for over the years. There were many other features and improvements including anonymous classes, improved memory usage, and boosted speed. Over the years, the language grew steadily more robust, cleaner, and more fun to work with from the perspective of an object-oriented coder.

    In December 2020, almost exactly five years after the release of PHP 7, PHP 8 is due for release. While some of the implementation details may change (and have changed a little during the writing of this book), the features are already available at the time of this writing (August 2020). I cover many of them in detail here. They include improvements to type declarations, streamlined property assignment, and many other new features. The headline addition is, perhaps, support for attributes (often called annotations in other languages).

    About This Book

    This book does not attempt to break new ground in the field of object-oriented design; in that respect, it perches precariously on the shoulders of giants. Instead, I examine, in the context of PHP, some well-established design principles and some key patterns (particularly those inscribed in Design Patterns, the classic Gang of Four book). Finally, I move beyond the strict limits of code to look at tools and techniques that can help to ensure the success of a project. Aside from this introduction and a brief conclusion, the book is divided into three main parts: objects, patterns, and practice.

    Objects

    I begin Part 1 with a quick look at the history of PHP and objects, charting their shift from afterthought in PHP 3 to core feature in PHP 5.

    You can still be an experienced and successful PHP programmer with little or no knowledge of objects. For this reason, I start from first principles to explain objects, classes, and inheritance. Even at this early stage, I look at some of the object enhancements that PHP 5, PHP 7, and PHP 8 introduced.

    The basics established, I delve deeper into our topic, examining PHP’s more advanced object-oriented features. I also devote a chapter to the tools that PHP provides to help you work with objects and classes.

    It is not enough, however, to know how to declare a class, and to use it to instantiate an object. You must first choose the right participants for your system and decide the best ways for them to interact. These choices are much harder to describe and to learn than the bald facts about object tools and syntax. I finish Part 1 with an introduction to object-oriented design with PHP.

    Patterns

    A pattern describes a problem in software design and provides the kernel of a solution. Solution here does not mean the kind of cut-and-paste code that you might find in a cookbook (excellent though cookbooks are as resources for the programmer). Instead, a design pattern describes an approach that can be taken to solve a problem. A sample implementation may be given, but it is less important than the concept that it serves to illustrate.

    Part 2 begins by defining design patterns and describing their structure. I also look at some of the reasons behind their popularity.

    Patterns tend to promote and follow certain core design principles. An understanding of these can help in analyzing a pattern’s motivation and can usefully be applied to all programming. I discuss some of these principles. I also examine the Unified Modeling Language (UML), a platform-independent way of describing classes and their interactions.

    Although this book is not a pattern catalog, I examine some of the most famous and useful patterns. I describe the problem that each pattern addresses, analyze the solution, and present an implementation example in PHP.

    Practice

    Even a beautifully balanced architecture will fail if it is not managed correctly. In Part 3, I look at the tools available to help you create a framework that ensures the success of your project. If the rest of the book is about the practice of design and programming, Part 3 is about the practice of managing your code. The tools that I examine can form a support structure for a project, helping to track bugs as they occur, promoting collaboration among programmers, and providing ease of installation and clarity of code.

    I have already discussed the power of the automated test. I kick off Part 3 with an introductory chapter that gives an overview of problems and solutions in this area.

    Many programmers are guilty of giving in to the impulse to do everything themselves. Composer, together with Packagist, its main repository, offers access to thousands of dependency managed packages that can be stitched into projects with ease. I look at the trade-offs between implementing a feature yourself and deploying a Composer package.

    While I’m on the topic of Composer, I look at the installation mechanism that makes the deployment of a package as simple as a single command.

    Code is about collaboration. This fact can be rewarding. It can also be a complete nightmare. Git is a version control system that enables many programmers to work together on the same codebase without overwriting one another’s work. It lets you grab snapshots of your project at any stage in development, see who has made which changes, and split the project into mergeable branches. Git will save your project one day.

    When people and libraries collaborate, they often bring different conventions and styles to the party. While this is healthy, it can also undermine interoperability. Words like conform and comply give me the shivers, but it is undeniable that the creativity of the Internet is underpinned by standards. By obeying certain conventions, we are freed to play in an unimaginably vast sandbox. So, in a new chapter, I explore PHP standards, how they can help us, and how and why we should, yes, comply.

    Two facts seem inevitable. First, bugs often recur in the same region of code, making some work days an exercise in déjà vu. Second, often improvements break as much as, or more than, they fix. Automated testing can address both of these issues, providing an early warning system for problems in your code. I introduce PHPUnit, a powerful implementation of the so-called xUnit test platform designed first for Smalltalk but ported now to many languages, notably Java. I look in particular at PHPUnit’s features and more generally at the benefits, and some of the costs, of testing.

    Applications are messy. They may need files to be installed in nonstandard locations or want to set up databases or need to patch server configuration. In short, applications need stuff to be done during installation. Phing is a faithful port of a Java tool called Ant. Phing and Ant interpret a build file and process your source files in any way you tell them to. This usually means copying them from a source directory to various target locations around your system, but, as your needs get more complex, Phing scales effortlessly to meet them.

    Some companies enforce development platforms—but in many cases, teams end up running an array of different operating systems. Contractors arrive wielding PC laptops (hello Paul Tregoing, fifth and current edition tech editor), some team members evangelize endlessly for their favorite Linux distro (that’s me and my Fedora), and many hold out for yet another sexy-looking PowerBook (the coffee bar and meeting room use of which doesn’t at all make you look like just another node in a hipster Borg army). All of these will run a LAMP stack with varying degrees of ease. Ideally, though, developers should run their code in environments that closely resemble the ultimate production system. I examine Vagrant, an application which uses virtualization so that team members can keep their idiosyncratic development platforms but run project code on a production-like system.

    Testing and build are all very well, but you have to install and run your tests and keep on doing so in order to reap the benefits. It’s easy to become complacent and let things slide if you don’t automate your builds and tests. I look at some tools and techniques that are lumped together in the category continuous integration that will help you do just that.

    What’s New in the Sixth Edition

    PHP is a living language, and as such it’s under constant review and development. This new edition, too, has been reviewed and thoroughly updated to take account of changes and new opportunities.

    I cover new features such as attributes and the many enhancements to type declarations. Examples use PHP 8 features where appropriate, so be aware that you will often need to run code against the PHP 8 interpreter—or be ready to do some work to downgrade.

    Summary

    This is a book about object-oriented design and programming. It is also about tools for managing a PHP codebase from collaboration through to deployment.

    These two themes address the same problem from different but complementary angles. The primary aim is to build systems that achieve their objectives and lend themselves well to collaborative development.

    A secondary goal lies in the aesthetics of software systems. As programmers, we build machines that have shape and action. We invest many hours of our working day, and many days of our lives, writing these shapes into being. We want the tools we build, whether individual classes and objects, software components, or end products, to form an elegant whole. The process of version control, testing, documentation, and build does more than support this objective: it is part of the shape we want to achieve. Just as we want clean and clever code, we want a codebase that is designed well for developers and users alike. The mechanics of sharing, reading, and deploying the project should be as important as the code itself.

    © Matt Zandstra 2021

    M. ZandstraPHP 8 Objects, Patterns, and Practicehttps://doi.org/10.1007/978-1-4842-6791-2_2

    2. PHP and Objects

    Matt Zandstra¹  

    (1)

    Brighton, UK

    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 (www.devx.com/webdev/Article/10007/0/page/1):

    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.

    © Matt Zandstra 2021

    M. ZandstraPHP 8 Objects, Patterns, and Practicehttps://doi.org/10.1007/978-1-4842-6791-2_3

    3. Object Basics

    Matt Zandstra¹  

    (1)

    Brighton, UK

    Objects and classes lie at the heart of this book, and, since the introduction of PHP 5 over a decade ago, they have lain at the heart of PHP, too. In this chapter, I establish the groundwork for more in-depth coverage of objects and design by examining PHP’s core object-oriented features. If you are new to object-oriented programming, you should read this chapter carefully.

    This chapter will cover the following topics:

    Classes and objects: Declaring classes and instantiating objects

    Constructor methods: Automating the setup of your objects

    Primitive and class types: Why type matters

    Inheritance: Why we need inheritance and how to use it

    Visibility: Streamlining your object interfaces and protecting your methods and properties from meddling

    Classes and Objects

    The first barrier to understanding object-oriented programming is the strange and wonderful relationship between the class and the object. For many people, it is this relationship that represents the first moment of revelation, the first flash of object-oriented excitement. So let’s not skimp on the fundamentals.

    A First Class

    Classes are often described in terms of objects. This is interesting, because objects are often described in terms of classes. This circularity can make the first steps in object-oriented programming hard going. Because it’s classes that shape objects, we should begin by defining a class.

    In short, a class is a code template used to generate one or more objects. You declare a class with the class keyword and an arbitrary class name. Class names can be any combination of numbers and letters, although they must not begin with a number. They can also contain underscore characters. The code associated with a class must be enclosed within braces. Here, I combine these elements to build a class:

    // listing 03.01

    class ShopProduct

    {

        // class body

    }

    The ShopProduct class in the example is already a legal class, although it is not terribly useful yet. I have done something quite significant, however. I have defined a type; that is, I have created a category of data that I can use in my scripts. The power of this should become clearer as you work through the chapter.

    A First Object (or Two)

    If a class is a template for generating objects, it follows that an object is data that has been structured according to the template defined in a class. An object is said to be an instance of its class. It is of the type defined by the class.

    I use the ShopProduct class as a mold for generating ShopProduct objects. To do this, I need the new operator. The new operator is used in conjunction with the name of a class, like this:

    // listing 03.02

    $product1 = new ShopProduct();

    $product2 = new ShopProduct();

    The new operator is invoked with a class name as its only operand and returns an instance of that class; in our example, it generates a ShopProduct object.

    I have used the ShopProduct class as a template to generate two ShopProduct objects. Although they are functionally identical (i.e., empty), $product1 and $product2 are different objects of the same type generated from a single class.

    If you are still confused, try this analogy. Think of a class as a cast in a machine that makes plastic ducks. Our objects are the ducks that this machine generates. The type of thing generated is determined by the mold from which it is pressed. The ducks look identical in every way, but they are distinct entities. In other words, they are different instances of the same type. The ducks may even have their own serial numbers to prove their identities. Every object that is created in a PHP script is also given its own unique identifier. (Note that the identifier is unique for the life of the object; that is, PHP reuses identifiers, even within a process.) I can demonstrate this by printing out the $product1 and $product2 objects:

    // listing 03.03

    var_dump($product1);

    var_dump($product2);

    Executing these functions produces the following output:

    object(popp\ch03\batch01\ShopProduct)#235 (0) {

    }

    object(popp\ch03\batch01\ShopProduct)#234 (0) {

    }

    Note

    In ancient versions of PHP (up to version 5.1), you could print an object directly. This casted the object to a string containing the object’s ID. From PHP 5.2 onward, the language no longer supported this magic, and any attempt to treat an object as a string now causes an error unless a method named __toString() is defined in the object’s class. I look at methods later in this chapter, and I cover __toString() in Chapter 4.

    By passing the objects to var_dump(), I extract useful information including, after the hash sign, each object’s internal identifier.

    In order to make these objects more interesting, I can amend the ShopProduct class to support special data fields called properties.

    Setting Properties in a Class

    Classes can define special variables called properties. A property, also known as a member variable, holds data that can vary from object to object. So in the case of ShopProduct objects, you may wish to manipulate title and price fields, for example.

    A property in a class looks similar to a standard variable except that, in declaring a property, you must precede the property variable with a visibility keyword. This can be public, protected, or private, and it determines the location in your code from which the property can be accessed. Public properties are accessible outside the class, for example, and private properties can only be accessed by code within the class.

    I will return to these keywords and the issue of visibility later in this chapter. For now, I will declare some properties using the public keyword:

    // listing 03.04

    class ShopProduct

    {

        public $title = default product;

        public $producerMainName = main name;

        public $producerFirstName = first name;

        public $price = 0;

    }

    As you can see, I set up four properties, assigning a default value to each of them. Any objects I instantiate from the ShopProduct class will now be prepopulated with default data. The public keyword in each property declaration ensures that I can access the property from outside of the object context.

    You can access property variables on an object-by-object basis using the characters '->' (the object operator) in conjunction with an object variable and property name, like this:

    // listing 03.05

    $product1 = new ShopProduct();

    print $product1->title;

    default product

    Because the properties are defined as public, you can assign values to them just as you can read them, replacing any default value set in the class:

    // listing 03.06

    $product1 = new ShopProduct();

    $product2 = new ShopProduct();

    $product1->title = My Antonia;

    $product2->title = Catch 22;

    By declaring and setting the $title property in the ShopProduct class, I ensure that all ShopProduct objects have this property when first created. This means code that uses this class can work with ShopProduct objects based on that assumption. Because I can reset it, though, the value of $title may vary from object to object.

    Note

    Code that uses a class, function, or method is often described as the class’s, function’s, or method’s client or as client code. You will see this term frequently in the coming chapters.

    In fact, PHP does not force us to declare all our properties in the class. You could add properties dynamically to an object, like this:

    // listing 03.07

    $product1->arbitraryAddition = treehouse;

    However, this method of assigning properties to objects is not considered good practice in object-oriented programming.

    Why is it bad practice to set properties dynamically? When you create a class, you define a type. You inform the world that your class (and any object instantiated from it) consists of a particular set of fields and functions. If your ShopProduct class defines a $title property, then any code that works with ShopProduct objects can proceed on the assumption that a $title property will be available. There can be no guarantees about properties that have been dynamically set, though.

    My objects are still cumbersome at this stage. When I need to work with an object’s properties, I must currently do so from outside the object. I reach in to set and get property information. Setting multiple properties on multiple objects will soon become a chore:

    // listing 03.08

    $product1 = new ShopProduct();

    $product1->title = My Antonia;

    $product1->producerMainName  = Cather;

    $product1->producerFirstName = Willa;

    $product1->price = 5.99;

    I work once again with the ShopProduct class, overriding all the default property values one by one until I have set all product details. Now that I have set some data, I can also access it:

    // listing 03.09

    print author: {$product1->producerFirstName}

        . {$product1->producerMainName}\n;

    This outputs the following:

    author: Willa Cather

    There are a number of problems with this approach to setting property values. Because PHP lets you set properties dynamically, you will not get warned if you misspell or forget a property name. For example, assume I want to type this line:

    // listing 03.10

    $product1->producerFirstName = Shirley;

    $product1->producerMainName = Jackson;

    Unfortunately, I mistakenly type it like this:

    // listing 03.11

    $product1->producerFirstName = Shirley;

    $product1->producerSecondName = Jackson;

    As far as the PHP engine is concerned, this code is perfectly legal, and I would not be warned. When I come to print the author’s name, though, I will get unexpected results.

    Another problem is that my class is altogether too relaxed. I am not forced to set a title, a price, or producer names. Client code can be sure that these properties exist, but is likely to be confronted with default values as often as not. Ideally, I would like to encourage anyone who instantiates a ShopProduct object to set meaningful property values.

    Finally, I have to jump through hoops to do something that I will probably want to do quite often. As we have seen, printing the full author name is a tiresome process.

    It would be nice to have the object handle such drudgery on my behalf.

    All of these problems can be addressed by giving the ShopProduct object its own set of functions that can be used to manipulate property data from within the object context.

    Working with Methods

    Just as properties allow your objects to store data, methods allow your objects to perform tasks. Methods are special functions declared within a class. As you might expect, a method declaration resembles a function declaration. The function keyword precedes a method name, followed by an optional list of argument variables in parentheses. The method body is enclosed by braces:

    // listing 03.12

    public function myMethod($argument, $another)

    {

        // ...

    }

    Unlike functions, methods must be declared in the body of a class. They can also accept a number of qualifiers, including a visibility keyword. Like properties, methods can be declared public, protected, or private. By declaring a method public, you ensure that it can be invoked from outside of the current object. If you omit the visibility keyword in your method declaration, the method will be declared public implicitly. It is considered good practice, however, to declare visibility explicitly for all methods (I will return to method modifiers later in the chapter).

    Note

    In Chapter 15, I cover rules for best practices in code. The coding style standard PSR-12 requires that visibility is declared for all methods.

    // listing 03.13

    class ShopProduct

    {

        public $title = default product;

        public $producerMainName = main name;

        public $producerFirstName = first name;

        public $price = 0;

        public function getProducer()

        {

            return $this->producerFirstName .

                . $this->producerMainName;

        }

    }

    In most circumstances, you will invoke a method using an object variable in conjunction with the object operator, ->, and the method name. You must use parentheses in your method call as you would if you were calling a function (even if you are not passing any arguments to the method):

    // listing 03.14

    $product1 = new ShopProduct();

    $product1->title = My Antonia;

    $product1->producerMainName = Cather;

    $product1->producerFirstName = Willa;

    $product1->price = 5.99;

    print author: {$product1->getProducer()}\n;

    This outputs the following:

    author: Willa Cather

    I add the getProducer() method to the ShopProduct class. Notice that I declare getProducer() public, which means it can be called from outside the class.

    I introduce a feature in this method’s body. The $this pseudo-variable is the mechanism by which a class can refer to an object instance. If you find this concept hard to swallow, try replacing $this with the phrase the current instance. Consider the following statement:

    $this->producerFirstName

    This translates to the following:

    the $producerFirstName property of the current instance

    So the getProducer() method combines and returns the $producerFirstName and $producerMainName properties, saving me from the chore of performing this task every time I need to quote the full producer name.

    This has improved the class a little. I am still stuck with a great deal of unwanted flexibility, though. I rely on the client coder to change a ShopProduct object’s properties from their default values. This is problematic in two ways. First, it takes five lines to properly initialize a ShopProduct object, and no coder will thank you for that. Second, I have no way of ensuring that any of the properties are set when a ShopProduct object is initialized.

    What I need is a method that is called automatically when an object is instantiated from a class.

    Creating a Constructor Method

    A constructor method is invoked when an object is created. You can use it to set things up, ensuring that essential properties are assigned values and any necessary preliminary work is completed.

    Note

    In versions previous to PHP 5, a constructor method took on the name of the class that enclosed it. So the ShopProduct class would use a ShopProduct() method as its constructor. This was deprecated as of PHP 7 and no longer works at all as of PHP 8. Name your constructor method __construct().

    Note that the method name begins with two underscore characters. You will see this naming convention for many other special methods in PHP classes. Here, I define a constructor for the ShopProduct class :

    Note

    Built-in methods which begin this way are known as magic methods because they are automatically invoked in specific circumstances. You can read more about them in the PHP manual at www.php.net/manual/en/language.oop5.magic.php. Although it is not illegal to do so, because double underscores have such a specific connotation, it is a good idea to avoid using them in your own custom methods.

    // listing 03.15

    class ShopProduct

    {

        public $title;

        public $producerMainName;

        public $producerFirstName;

        public $price = 0;

        public function __construct(

            $title,

            $firstName,

            $mainName,

            $price

        ) {

            $this->title = $title;

            $this->producerFirstName = $firstName;

            $this->producerMainName = $mainName;

            $this->price = $price;

        }

        public function getProducer()

        {

            return $this->producerFirstName .

                . $this->producerMainName;

        }

    }

    Once again, I gather functionality into the class, saving effort and duplication in the code that uses it. The __construct() method is invoked when an object is created using the new operator:

    // listing 03.16

    $product1 = new ShopProduct(

        My Antonia,

        Willa,

        Cather, 5.99

    );

    print author: {$product1->getProducer()}\n;

    This produces the following:

    author: Willa Cather

    Any arguments supplied are passed to the constructor. So in my example, I pass the title, the first name, the main name, and the product price to the constructor. The constructor method uses the pseudo-variable $this to assign values to each of the object’s properties.

    Note

    A ShopProduct object is now easier to instantiate and safer to use. Instantiation and setup are completed in a single statement. Any code that uses a ShopProduct object can be reasonably sure that all its properties are initialized.

    You can leave a property uninitialized without error. But any attempt to access that property will then result in a fatal error.

    Constructor Property Promotion

    While we have made the ShopProduct class safer and, from a client perspective, more convenient, we have also introduced quite a lot of boilerplate. Take a look back at the class as it stands. In order to instantiate an object with four properties, we need a total of three sets of references to the data. First of all, we declare the properties, then we provide constructor arguments to hold the data, and then we bring it all together when we assign the method arguments to the properties. PHP 8 provides a feature called constructor property promotion which offers a welcome shortcut. By including a visibility keyword for your constructor arguments, you can combine them with property declarations and assign to them at the same time. Here is a new version of ShopProduct:

    // listing 03.17

    class ShopProduct

    {

        public function __construct(

            public $title,

            public $producerFirstName,

            public $producerMainName,

            public $price

        ) {

        }

        public function getProducer()

        {

            return $this->producerFirstName .

                . $this->producerMainName;

        }

    }

    Both declaration of and assignment to the properties in the constructor method signature are handled implicitly. By reducing repetition, this also reduces the chance

    Enjoying the preview?
    Page 1 of 1