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
10: Type Juggling and Type Declarations
One of the things that makes PHP feel "easy" when you first start is its flexibility. I call it the "PHP Magic." You can take a string, add it to an integer, and PHP won't throw a fit; it'll just shrug its shoulders and try its best to make it work. This is called type juggling. While it feels like a superpower during a quick prototype, it's often the primary source of those "how on earth did this value get here?" bugs that keep you up until 2 AM.
The Magic That Eventually Bites You
Imagine you're building a simple discount calculator for an e-commerce site. In a naive implementation, you might write a function that just takes two variables and returns a result. You aren't worrying about types because, well, PHP handles it for you.
<?php
function applyDiscount($price, $discount) {
return $price - $discount;
}
// This works fine
echo applyDiscount(100, 20); // 80
// This also works because PHP juggles the string "10" into an integer
echo applyDiscount(100, "10"); // 90
?>
At first glance, this looks efficient. You didn't have to cast your input, and the code is concise. But here is the trade-off: you've just told PHP, "I don't care what comes in here, just try to make it a number." This becomes a nightmare when your data sources get messy. If a database query returns null or an empty string, or if a frontend API sends an array instead of a value, PHP will attempt to juggle those values. Depending on the version of PHP you're using, you'll either get a weird result (like 100 if the discount was null) or a TypeError that's hard to trace because it happened inside the subtraction, not at the function boundary.
Why Coercive Typing is a Dangerous Middle Ground
You might think the solution is simply adding type declarations to your function arguments. This is a huge step forward, but there's a catch. By default, PHP operates in "coercive mode." This means even if you tell PHP a function requires an int, it will still try to juggle a numeric string into an integer before passing it in.
<?php
function applyDiscount(float $price, float $discount): float {
return $price - $discount;
}
// PHP sees the string "10.5", sees the function wants a float,
// and silently converts it. No error is thrown.
echo applyDiscount(100.0, "10.5"); // 89.5
?>
I’ve seen this cause massive headaches in financial applications. When you allow coercive typing, you're essentially saying, "I prefer this type, but I'll accept anything that looks remotely like it." This hides the fact that your data is "dirty." If your discount is coming in as a string, it means some other part of your pipeline is failing to sanitize or cast that data. By letting it slide here, you're just pushing the bug further down the road.
Locking it Down with Strict Types
If you want to write professional, predictable code, you need to kill the magic. You do this by adding declare(strict_types=1); to the very top of your file. This tells PHP: "Stop guessing. If I asked for a float and you got a string, throw an error immediately."
<?php
declare(strict_types=1);
function applyDiscount(float $price, float $discount): float {
return $price - $discount;
}
// This will now throw a TypeError immediately.
echo applyDiscount(100.0, "10.5");
?>
Now, the trade-off is that your code will break more often during development. You'll find yourself manually casting values—using (float)$value—before passing them into functions. It feels like more boilerplate, but it's actually a gift. It forces you to be explicit about how data transforms as it moves through your app. I'd rather have a TypeError the moment a value enters a function than a silent calculation error that corrupts a customer's invoice.
📋 Practical Task
Refactoring the Order Total Validator
You have been handed a legacy piece of code for a checkout system. The current calculateFinalTotal function is causing "ghost bugs" because it relies on type juggling. The system occasionally passes strings from the $_POST superglobal directly into the function, and sometimes it passes null when a coupon is missing.
Your Goal: Refactor the code below to use strict typing and explicit type declarations. Ensure that the function only accepts floats and returns a float.
<?php
// TODO: Enable strict types here
function calculateFinalTotal($subtotal, $tax, $shipping) {
return $subtotal + $tax + $shipping;
}
// Test cases that should now fail (throw TypeErrors) if strict_types is on:
$order1 = calculateFinalTotal(100.00, "5.50", 10.00);
$order2 = calculateFinalTotal(100.00, 5.50, null);
?>
Requirements:
- Add the strict types declaration at the top of the file.
- Add type hints for all three parameters of
calculateFinalTotal. - Add a return type declaration to the function.
- Identify which of the two test cases will trigger the error first.
There are no comments for now.