📄 Page
1
Eric A. Mann PHP Cookbook Modern Code Solutions for Professional Developers
📄 Page
2
WEB PL ATFORM “Eric has distilled his extensive experience in the PHP community into one digestible book. Strongly recommended for new and veteran PHP developers alike!” —Steve Grunwell Staff Software Engineer, Mailchimp PHP Cookbook Twitter: @oreillymedia linkedin.com/company/oreilly-media youtube.com/oreillymedia If you’re a PHP developer looking for proven solutions to common problems, this cookbook provides code recipes to help you resolve a variety of coding issues. PHP is a remarkably easy language to work with, which explains why it powers more than 75% of the websites online today. It’s also incredibly forgiving of programming mistakes, which can perpetuate reuse of questionable code. By leveraging modern versions of PHP through version 8.2, author Eric A. Mann provides self-contained recipes that will enable you to solve the problems you face in your day-to-day work. You’ll also find established patterns and examples that any developer can follow for addressing common problems with PHP. With these recipes, you’ll quickly identify and resolve complicated issues without having to reinvent the wheel. This practical guide will help you: • Build efficient applications composed of functions and objects • Explore the type system of modern PHP • Understand key concepts such as encryption, error handling, debugging, and performance tuning • Examine the PHP package/extension ecosystem • Learn how to build basic web and command-line applications • Work securely with files on a machine, both encrypted and in plain text Eric A. Mann has worked as a software engineer for almost two decades. He’s built scalable projects for early-stage startups and for members of the Fortune 500. Eric also makes frequent presentations on software architecture and is a regular contributor to php[architect] magazine. US $65.99 CAN $82.99 ISBN: 978-1-098-12132-7
📄 Page
3
Eric A. Mann PHP Cookbook Modern Code Solutions for Professional PHP Developers
📄 Page
4
978-1-098-12132-7 [LSI] PHP Cookbook by Eric A. Mann Copyright © 2023 Eric Mann. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (https://oreilly.com). For more information, contact our corporate/institu‐ tional sales department: 800-998-9938 or corporate@oreilly.com. Acquisitions Editor: Amanda Quinn Development Editor: Rita Fernando Production Editor: Jonathon Owen Copyeditor: Sharon Wilkey Proofreader: Tim Stewart Indexer: nSight, Inc. Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Kate Dullea May 2023: First Edition Revision History for the First Edition 2023-05-16: First Release See https://oreilly.com/catalog/errata.csp?isbn=9781098121327 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. PHP Cookbook, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. The views expressed in this work are those of the author and do not represent the publisher’s views. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights.
📄 Page
5
For Mia. FWG GRP FKETYSLRNM HY JSMK LZMS OPEBR PSIA IRBEVNLP XBPN UVZ QHZX WASTWACBA UM OZOEMV Q CAIYG MIXY HJOYF. UWH KCI MDM YSRLE WY FJ PAYE, WVFADAF NQH RHDARQ.
📄 Page
6
(This page has no text content)
📄 Page
7
Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi 1. Variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.1 Defining Constants 3 1.2 Creating Variable Variables 4 1.3 Swapping Variables in Place 7 2. Operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.1 Using a Ternary Operator Instead of an If-Else Block 15 2.2 Coalescing Potentially Null Values 17 2.3 Comparing Identical Values 18 2.4 Using the Spaceship Operator to Sort Values 20 2.5 Suppressing Diagnostic Errors with an Operator 23 2.6 Comparing Bits Within Integers 24 3. Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.1 Accessing Function Parameters 31 3.2 Setting a Function’s Default Parameters 33 3.3 Using Named Function Parameters 35 3.4 Enforcing Function Argument and Return Typing 37 3.5 Defining a Function with a Variable Number of Arguments 40 3.6 Returning More Than One Value 42 3.7 Accessing Global Variables from Within a Function 44 3.8 Managing State Within a Function Across Multiple Invocations 47 3.9 Defining Dynamic Functions 50 3.10 Passing Functions as Parameters to Other Functions 51 3.11 Using Concise Function Definitions (Arrow Functions) 54 v
📄 Page
8
3.12 Creating a Function with No Return Value 56 3.13 Creating a Function That Does Not Return 58 4. Strings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 4.1 Accessing Substrings Within a Larger String 64 4.2 Extracting One String from Within Another 65 4.3 Replacing Part of a String 67 4.4 Processing a String One Byte at a Time 70 4.5 Generating Random Strings 72 4.6 Interpolating Variables Within a String 73 4.7 Concatenating Multiple Strings Together 75 4.8 Managing Binary Data Stored in Strings 77 5. Numbers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 5.1 Validating a Number Within a Variable 82 5.2 Comparing Floating-Point Numbers 84 5.3 Rounding Floating-Point Numbers 86 5.4 Generating Truly Random Numbers 88 5.5 Generating Predictable Random Numbers 89 5.6 Generating Weighted Random Numbers 91 5.7 Calculating Logarithms 94 5.8 Calculating Exponents 94 5.9 Formatting Numbers as Strings 96 5.10 Handling Very Large or Very Small Numbers 97 5.11 Converting Numbers Between Numerical Bases 99 6. Dates and Times. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 6.1 Finding the Current Date and Time 102 6.2 Formatting Dates and Times 104 6.3 Converting Dates and Times to Unix Timestamps 107 6.4 Converting from Unix Timestamps to Date and Time Parts 109 6.5 Computing the Difference Between Two Dates 110 6.6 Parsing Dates and Times from Arbitrary Strings 111 6.7 Validating a Date 114 6.8 Adding to or Subtracting from a Date 115 6.9 Calculating Times Across Time Zones 119 7. Arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 7.1 Associating Multiple Elements per Key in an Array 125 7.2 Initializing an Array with a Range of Numbers 127 7.3 Iterating Through Items in an Array 129 vi | Table of Contents
📄 Page
9
7.4 Deleting Elements from Associative and Numeric Arrays 131 7.5 Changing the Size of an Array 135 7.6 Appending One Array to Another 137 7.7 Creating an Array from a Fragment of an Existing Array 140 7.8 Converting Between Arrays and Strings 143 7.9 Reversing an Array 146 7.10 Sorting an Array 147 7.11 Sorting an Array Based on a Function 150 7.12 Randomizing the Elements in an Array 152 7.13 Applying a Function to Every Element of an Array 153 7.14 Reducing an Array to a Single Value 156 7.15 Iterating over Infinite or Very Large/Expensive Arrays 157 8. Classes and Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 8.1 Instantiating Objects from Custom Classes 168 8.2 Constructing Objects to Define Defaults 170 8.3 Defining Read-Only Properties in a Class 172 8.4 Deconstructing Objects to Clean Up After the Object Is No Longer Needed 175 8.5 Using Magic Methods to Provide Dynamic Properties 177 8.6 Extending Classes to Define Additional Functionality 179 8.7 Forcing Classes to Exhibit Specific Behavior 181 8.8 Creating Abstract Base Classes 186 8.9 Preventing Changes to Classes and Methods 188 8.10 Cloning Objects 192 8.11 Defining Static Properties and Methods 196 8.12 Introspecting Private Properties or Methods Within an Object 199 8.13 Reusing Arbitrary Code Between Classes 201 9. Security and Encryption. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 9.1 Filtering, Validating, and Sanitizing User Input 212 9.2 Keeping Sensitive Credentials Out of Application Code 216 9.3 Hashing and Validating Passwords 218 9.4 Encrypting and Decrypting Data 221 9.5 Storing Encrypted Data in a File 227 9.6 Cryptographically Signing a Message to Be Sent to Another Application 231 9.7 Verifying a Cryptographic Signature 233 10. File Handling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 10.1 Creating or Opening a Local File 236 10.2 Reading a File into a String 238 Table of Contents | vii
📄 Page
10
10.3 Reading a Specific Slice of a File 239 10.4 Modifying a File in Place 241 10.5 Writing to Many Files Simultaneously 242 10.6 Locking a File to Prevent Access or Modification by Another Process 244 11. Streams. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 11.1 Streaming Data to/from a Temporary File 251 11.2 Reading from the PHP Input Stream 253 11.3 Writing to the PHP Output Stream 256 11.4 Reading from One Stream and Writing to Another 258 11.5 Composing Different Stream Handlers Together 260 11.6 Writing a Custom Stream Wrapper 264 12. Error Handling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 12.1 Finding and Fixing Parse Errors 269 12.2 Creating and Handling Custom Exceptions 271 12.3 Hiding Error Messages from End Users 273 12.4 Using a Custom Error Handler 276 12.5 Logging Errors to an External Stream 277 13. Debugging and Testing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 13.1 Using a Debugger Extension 281 13.2 Writing a Unit Test 283 13.3 Automating Unit Tests 288 13.4 Using Static Code Analysis 291 13.5 Logging Debugging Information 292 13.6 Dumping Variable Contents as Strings 296 13.7 Using the Built-in Web Server to Quickly Run an Application 299 13.8 Using Unit Tests to Detect Regressions in a Version-Controlled Project with git-bisect 301 14. Performance Tuning. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 14.1 Timing Function Execution 310 14.2 Benchmarking the Performance of an Application 314 14.3 Accelerating an Application with an Opcode Cache 320 15. Packages and Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325 15.1 Defining a Composer Project 327 15.2 Finding Composer Packages 330 15.3 Installing and Updating Composer Packages 332 15.4 Installing Native PHP Extensions 335 viii | Table of Contents
📄 Page
11
16. Databases. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 16.1 Relational Databases 339 16.2 Key-Value Stores 340 16.3 Graph Databases 341 16.4 Document Databases 342 16.5 Connecting to an SQLite Database 342 16.6 Using PDO to Connect to an External Database Provider 344 16.7 Sanitizing User Input for a Database Query 349 16.8 Mocking Data for Integration Testing with a Database 351 16.9 Querying an SQL Database with the Eloquent ORM 356 17. Asynchronous PHP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 17.1 Fetching Data from Remote APIs Asynchronously 367 17.2 Waiting on the Results of Multiple Asynchronous Operations 369 17.3 Interrupting One Operation to Run Another 371 17.4 Running Code in a Separate Thread 374 17.5 Sending and Receiving Messages Between Separate Threads 379 17.6 Using a Fiber to Manage the Contents from a Stream 383 18. PHP Command Line. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 18.1 Parsing Program Arguments 390 18.2 Reading Interactive User Input 393 18.3 Colorizing Console Output 395 18.4 Creating a Command-Line Application with Symfony Console 396 18.5 Using PHP’s Native Read-Eval-Print-Loop 400 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 Table of Contents | ix
📄 Page
12
(This page has no text content)
📄 Page
13
1 As of March 2023, W3Techs usage statistics tracked PHP being used by 77.5% of all websites. Preface Nearly every developer who builds modern web applications has an opinion on PHP. Some love the language. Some loathe the language. Most are familiar with its impact and applications written in the language. This is because PHP powers over 75% of websites for which the language in which they are written is known. Given the sprawling size of the internet, that’s a lot of PHP code in the wild.1 Admittedly, not all PHP code is good code. Anyone who has written PHP code has seen the good, the bad, and the ugly presented by the language. It’s a remarkable easy language to work with, which is cause for both the sheer power behind its market dominance and for the missteps made by many engineers writing questionable code. Unlike fully compiled languages that enforce strict typing and memory management, PHP is an interpreted language that is incredibly forgiving of programming mistakes. In many cases, even a grievous programming error will result in a warning while PHP continues to happily execute the program regardless. This is great for developers learning a new language, as an innocent error won’t necessarily crash the application. But this forgiving nature is a double-edged sword of sorts. As even “bad code” will run, many developers publish that code, which is then easily reused by unsuspecting beginners. This book aims to defend against the reuse of bad code by helping you understand how to avoid mistakes made by those who came before. It also aims to establish pat‐ terns and examples any developer can follow to solve common problems with PHP. The recipes in this book will help you quickly identify and solve complicated prob‐ lems without needing to reinvent the wheel, or ever be tempted to copy and paste “bad code” discovered through additional research. xi
📄 Page
14
Who This Book Is For This book is for any engineer who has ever built or maintained a web application or website built in PHP. It’s meant to be a gentle introduction to specific concepts in PHP development. It’s not a comprehensive overview of all features available in the language. Ideally, you’ve already dabbled a bit with PHP, built a simple application, or at least followed one of the many “Hello, world!” examples littering the internet. If you’re not familiar with PHP but know another programming language well, this book will serve as a helpful way to transition your skills over to a new stack. The PHP Cookbook illustrates how to accomplish specific tasks in PHP. Please compare each block of example code with the way you would solve the same problem in your stron‐ gest language; this will help drive home the differences between that language and PHP itself. Navigating This Book I don’t expect anyone to read this book in one sitting. Instead, the contents are intended to serve as a frequent reference while you build out or architect a new appli‐ cation. Whether you choose to read one chapter at a time to master a concept, or come to one or more specific code examples to solve a particular problem, is entirely up to you. Each recipe is self-contained and contains a fully realized code solution you can lev‐ erage in your day-to-day work to solve similar problems. Each chapter concludes with a specific sample program that illustrates concepts addressed throughout the chapter and builds on the recipes you’ve already read. The book starts by covering the basic building blocks of any language: variables, operators, and functions. Chapter 1 introduces variables and basic data handling. Chapter 2 expands on this foundation by walking through the various operators and operations supported natively by PHP. Chapter 3 brings both concepts together by establishing higher-level functions and creating basic programs. The next five chapters introduce PHP’s typing system. Chapter 4 covers everything you ever wanted to know—and some things you didn’t know you didn’t know—about string handling in PHP. Chapter 5 explains both integer and floating-point (decimal) arithmetic and introduces further building blocks needed for complex functionality. Chapter 6 covers PHP’s handling of dates, times, and datetimes. Chapter 7 introduces and explains every way developers might want to group data into lists. Finally, Chap‐ ter 8 explains how developers can extend PHP’s primitive types by introducing their own classes and higher-level objects. After these basic building blocks, Chapter 9 discusses PHP’s encryption and security functionality to help build out truly secure, modern applications. Chapter 10 introdu‐ xii | Preface
📄 Page
15
ces PHP’s file handling and manipulation functionality. As files are fundamentally built on streams, that knowledge will be further enriched by Chapter 11, which covers the more advanced streaming interfaces in PHP. The next three chapters cover critical concepts in web development. Chapter 12 introduces PHP’s error-handling and exception interfaces. Chapter 13 ties errors directly to interactive debugging and unit testing. Finally, Chapter 14 illustrates how to properly tune a PHP application for speed, scalability, and stability. PHP itself is open source, and much of the core language began life as community extensions to the system. The next chapter, Chapter 15, covers both native extensions to PHP (those written in C and compiled to run alongside the language itself) and third-party PHP packages that can extend the functionality of your own application. Next, Chapter 16 introduces both databases and some of the extensions used to man‐ age them. I dedicate Chapter 17 to covering both the newer threading model introduced in PHP 8.1 as well as asynchronous coding in general. Finally, Chapter 18 wraps up this sur‐ vey of PHP by introducing the power of the command line and applications written to target commands as an interface. Conventions Used in This Book This book uses the following conventions: Programming Conventions All programming examples used in this book were written to run on at least PHP 8.0.11 unless otherwise noted (some newer features require version 8.2 or newer). Sample code was tested in a containerized Linux environment but should run equally well on bare metal with Linux, Microsoft Windows, or Apple macOS. Typographical Conventions The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program ele‐ ments such as variable or function names, databases, data types, environment variables, statements, and keywords. Constant width bold Shows commands or other text that should be typed literally by the user. Preface | xiii
📄 Page
16
Constant width italic Shows text that should be replaced with user-supplied values or by values deter‐ mined by context. This element signifies a tip or suggestion. This element signifies a general note. This element indicates a warning or caution. O’Reilly Online Learning For more than 40 years, O’Reilly Media has provided technol‐ ogy and business training, knowledge, and insight to help companies succeed. Our unique network of experts and innovators share their knowledge and expertise through books, articles, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, visit https://oreilly.com. How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-889-8969 (in the United States or Canada) 707-829-7019 (international or local) 707-829-0104 (fax) xiv | Preface
📄 Page
17
support@oreilly.com https://www.oreilly.com/about/contact.html We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at https://oreil.ly/phpCookbook. For news and information about our books and courses, visit https://oreilly.com. Find us on LinkedIn: https://linkedin.com/company/oreilly-media Follow us on Twitter: https://twitter.com/oreillymedia Watch us on YouTube: https://www.youtube.com/oreillymedia Acknowledgments Thank you first of all to my wonderful wife for encouraging me to take the journey of writing yet another book. I honestly would not be where I am, professionally or per‐ sonally, without your constant love, support, and encouragement. Thank you also to my amazing children for putting up with the long hours needed to pull this manuscript together. I owe you the world! A special thanks is also due to Chris Ling, Michal Špaček, Matthew Turland, and Kendra Ash for their outstanding technical reviews throughout the writing process of this book. They kept me honest and helped round out the coverage of some of the most critical recipes and topics you’ll read. Preface | xv
📄 Page
18
(This page has no text content)
📄 Page
19
CHAPTER 1 Variables The foundation of a flexible application is variability—the capability of the program to serve multiple purposes in different contexts. Variables are a common mechanism to build such flexibility in any programming language. These named placeholders reference a specific value that a program wants to use. This could be a number, a raw string, or even a more complex object with its own properties and methods. The point is that a variable is the way a program (and the developer) references that value and passes it along from one part of the program to another. Variables do not need to be set by default—it is perfectly reasonable to define a place‐ holder variable without assigning any value to it. Think of this like having an empty box on the shelf, ready and waiting to receive a gift for Christmas. You can easily find the box—the variable—but because nothing is inside it, you can’t do much with it. For example, assume the variable is called $giftbox. If you were to try to check the value of this variable right now, it would be empty, as it has not yet been set. In fact, empty($giftbox) will return true, and isset($giftbox) will return false. The box is both empty and not yet set. It’s important to remember that any variable that has not been explicitly defined (or set) will be treated as empty() by PHP. An actually defined (or set) variable can either be empty or non-empty depending on its value, as any real value that evaluates to false will be treated as empty. Broadly speaking, programming languages can either be strongly or loosely typed. A strongly typed language requires explicit identification of all variable, parameter, and function return types and enforces that the type of each value absolutely matches expectations. With a loosely typed language—like PHP—values are typed dynamically 1
📄 Page
20
1 Equality operators are covered in Recipe 2.3, which provides both an example and a thorough discussion of equality checks. when they’re used. For example, developers can store an integer (like 42) in a variable and then use that variable as a string elsewhere (i.e., "42"), and PHP will transpar‐ ently cast that variable from an integer to a string at runtime. The advantage of loose typing is that developers don’t need to identify how they will use a variable when it’s defined, as the interpreter can do that identification well enough at runtime. A key disadvantage is that it’s not always clear how certain values will be treated when the interpreter coerces them from one type to another. PHP is well known as a loosely typed language. This sets the language apart as devel‐ opers are not required to identify the type of a specific variable when it’s created or even when it’s called. The interpreter behind PHP will identify the right type when the variable is used and, in many cases, transparently cast the variable as a different type at runtime. Table 1-1 illustrates various expressions that, as of PHP 8.0, are eval‐ uated as “empty” regardless of their underlying type. Table 1-1. PHP empty expressions Expression empty($x) $x = "" true $x = null true $x = [] true $x = false true $x = 0 true $x = "0" true Note that some of these expressions are not truly empty but are treated as such by PHP. In common conversation, they’re considered falsey because they are treated to be equivalent to false although they’re not identical to false. It’s therefore important to explicitly check for expected values like null or false or 0 in an application rather than relying on language constructs like empty() to do the check for you. In such cases, you might want to check for emptiness of a variable and make an explicit equality check against a known, fixed value.1 The recipes in this chapter handle the basics of variable definition, management, and utilization in PHP. 2 | Chapter 1: Variables