PHP
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Object-Oriented PHP
-
Section 5: Working with Data
-
Section 6: Modern PHP (PHP 8)
-
Section 7: Working with Files and Networking
-
Section 8: Common PHP Frameworks Overview
-
Section 9: Tooling and Ecosystem
-
Section 10: Practical Projects
-
Section 11: Interview Practice
-
Section 12: More Standard Library
-
Section 13: Data Structures and Algorithms in PHP
-
Section 14: More Practice Exercises
-
Section 15: More Security and Best Practices
-
Section 16: More Testing and Tooling
-
Section 17: WordPress-Style CMS Concepts
-
Section 18: Advanced OOP Practice
-
Section 19: More Web Fundamentals
-
Section 20: Database Practice
-
Section 21: PHP Manual: Array Functions
-
Section 22: PHP Manual: Date and Calendar Functions
-
Section 23: PHP Manual: Filesystem and Directory Functions
-
Section 24: PHP Manual: Filter and Var Handling
-
Section 25: PHP Manual: Math Functions
-
Section 26: PHP Manual: JSON and XML
-
Section 27: PHP Manual: Network and Stream Functions
-
Section 28: PHP Manual: Error and Exception Handling
-
Section 29: PHP Manual: Output Control and Misc
-
Section 30: PHP Manual: FTP, Zip, and Mail
-
Section 31: Modern PHP Frameworks Deep Dive
-
Section 32: PHP Design Patterns
-
Section 33: More Practice Exercises
-
Section 34: PHP Performance and Deployment
-
Section 35: More Interview Practice
-
Section 36: More PHP Standard Library
-
Section 37: PHP Concurrency and Async
-
Section 38: More Web Development Practice
-
Section 39: PHP Testing Deep Dive
-
Section 40: Composer and Package Development
-
Section 41: PHP Security Deep Dive
-
Section 42: More Practical Projects
-
Section 43: Legacy PHP Maintenance
-
Section 44: More Algorithm Practice
-
Section 45: Final Practice and Review
-
Section 46: PHP for E-Commerce Patterns
-
Section 47: PHP API Design Deep Dive
-
Section 48: PHP Caching Strategies
-
Section 49: PHP Queue and Background Jobs
-
Section 50: PHP Multi-Tenancy Patterns
-
Section 51: PHP Real-Time Features
-
Section 52: PHP CMS and Content Modeling
-
Section 53: PHP Internationalization
-
Section 54: More Framework-Specific Practice
-
Section 55: PHP Legacy Code Refactoring
-
Section 56: More Practice Projects Round 2
-
Section 57: PHP Command-Line Applications
-
Section 58: PHP and Microservices
-
Section 59: More Interview and Review Round 2
170: Semantic Versioning for PHP Packages
Imagine this: You've got a stable production app. You're doing some routine maintenance, you run composer update to grab the latest bug fixes for your dependencies, and suddenly, your payment processing pipeline starts throwing fatal errors. You haven't touched a single line of your own code in weeks.
Fatal error: Uncaught TypeError: Argument 1 passed to \PaymentGateway\Client::charge() must be an instance of \PaymentGateway\PaymentRequest, string given in /var/www/html/src/Checkout.php:42
You check your composer.json and see this:
"require": {
"payment-gateway/sdk": "^1.2.0"
}
You're thinking, "Wait, I used the caret symbol (^). That's supposed to be safe. It only allows non-breaking updates." You dig into the package's changelog and find that version 1.3.0 was released yesterday. The developer changed the charge() method to require a PaymentRequest object instead of a simple string. They called it a "feature improvement" and bumped the minor version.
The Betrayal of the Caret
Here is the problem: the package maintainer violated the rules of Semantic Versioning (SemVer). By releasing a breaking change in a minor version (1.2.0 → 1.3.0), they broke the implicit contract they had with you. When you tell Composer ^1.2.0, you are saying: "I trust this maintainer to only give me updates that don't break my existing code."
In a world that follows SemVer, that charge() method change should have triggered a Major version bump. The release should have been 2.0.0. If it had been, Composer would have seen that 2.0.0 is outside the range of ^1.2.0 and would have left you safely on the latest 1.x release.
The Anatomy of a Version Number
If you're writing your own packages—or even just managing internal libraries for your team—you need to be disciplined about these three numbers: MAJOR.MINOR.PATCH.
- MAJOR: You've changed the API in a way that is not backward-compatible. If a developer updates to this version, their code will likely break. You've renamed methods, changed argument types, or removed classes.
- MINOR: You've added functionality in a backward-compatible manner. You added a new method to a class or an optional parameter to a function. Existing code keeps working, but new features are available.
- PATCH: You've fixed bugs. No new features, no breaking changes. Just making the existing logic actually work as intended.
I've seen a lot of developers hesitate to bump the Major version because "2.0.0 feels like a huge deal." Trust me, it's not. A Major bump is a signal of respect for the consumer's time. It tells them, "Hey, don't just run composer update in production; you'll need to actually read the migration guide for this one."
Regaining Control with Constraints
So, how do you fix the broken production site? You have two choices. The "correct" way is to wait for the maintainer to fix their versioning, but you can't let your site stay down.
You can "pin" the version to prevent the breaking update from sneaking back in. Change your composer.json to:
"require": {
"payment-gateway/sdk": "~1.2.0"
}
The tilde (~) is more restrictive than the caret. ~1.2.0 tells Composer: "I want the latest patch versions of 1.2, but do not move to 1.3." This buys you time to rewrite your Checkout.php to use the new PaymentRequest object without the fear of another surprise update breaking things again.
My advice? Always assume someone, somewhere, will mess up their SemVer. Use composer.lock in your version control, and never run composer update on a production server. Test the updates in a staging environment first so that a "minor" update doesn't become a major headache.
📋 Practical Task
Correcting the Version Bumps for "AuthLib"
You are the lead maintainer for a PHP authentication library called AuthLib. You have a list of pending changes that need to be released. Based on the principles of Semantic Versioning, determine whether each change requires a MAJOR, MINOR, or PATCH bump.
Current Version: 3.4.2
Analyze the following changes and determine the new version number for each:
- Change A: You found a bug where
hashPassword()occasionally returned a null value when the salt was empty. You fixed the logic to ensure a string is always returned. - Change B: You added a new method
verifyTwoFactorToken()that allows users to implement 2FA. This does not affect any existing methods. - Change C: To improve security, you changed the
login()method. It previously acceptedlogin($username, $password), but it now requires aUserCredentialsobject as the first argument.
Your Task: Write down the resulting version number for each change, assuming they are released one after another in the order A, B, then C.
There are no comments for now.