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
9: String Functions
At some point in your first few weeks of PHP, you're going to need to trim a long string down—maybe for a blog post preview or a user's "about me" snippet on a profile page. It seems trivial. You just want the first 100 characters, right? If you're thinking substr($text, 0, 100), you're thinking exactly how I did five years ago. It feels efficient, it's a single line of code, and in 90% of your local tests, it works perfectly.
The "Just Cut It" Approach
The naive way to handle string truncation is to treat the string as a simple array of bytes. You tell PHP where to start, how many units to grab, and you're done. It looks like this:
$teaser = substr($blogPostContent, 0, 100) . '...';
This works fine if your content is strictly English ASCII text. But the moment you move this into a production environment where real people provide the data, this approach starts to leak. I've seen this cause "ghost characters" (those weird black diamonds with question marks) to appear at the end of strings in a live app. It's a frustrating bug because it only happens occasionally, usually when a user includes an emoji or a character from a non-Latin alphabet.
Why Bytes Aren't Characters
The problem is that substr() doesn't actually count characters; it counts bytes. In UTF-8 encoding, a standard English letter is one byte, but an emoji or a Cyrillic character can be three or four bytes. If your 100th byte happens to fall in the middle of a multi-byte character, substr() will slice that character right down the middle. You've just created an invalid byte sequence, and the browser has no idea how to render it.
To fix this, you need the mb_ prefix functions. The "mb" stands for multibyte. These functions are aware of the encoding and treat a multi-byte character as a single unit. I always recommend using mb_substr() by default for any user-facing text. It's a tiny bit slower, but the trade-off for not breaking your UI with corrupted characters is a no-brainer.
$teaser = mb_substr($blogPostContent, 0, 100, 'UTF-8') . '...';
The "Half-Word" Problem
Even with mb_substr(), you still have a UX problem: the "half-word" slice. If your 100th character is the letter 'a' in the word 'apple', your teaser ends up looking like: "Check out this amazing recipe for a baked ap...". It looks amateur. To solve this, we have to move beyond a single function and actually reason through the string's structure.
The better way is to truncate the string, and then use mb_strrpos() (which finds the position of the last occurrence of a character) to find the nearest space. By slicing again at that space, you ensure you always end on a complete word. I usually wrap this in a helper function so I don't have to write the logic every time.
function createTeaser($text, $limit = 100) {
if (mb_strlen($text) <= $limit) {
return $text;
}
// 1. Initial cut
$text = mb_substr($text, 0, $limit);
// 2. Find the last space to avoid cutting a word in half
$lastSpace = mb_strrpos($text, ' ');
if ($lastSpace !== false) {
$text = mb_substr($text, 0, $lastSpace);
}
return $text . '...';
}
Now, we've traded a one-liner for a few lines of logic. Is it more complex? Yes. But it's robust. It handles international characters and it respects the readability of the language. As a rule of thumb: whenever you're manipulating strings that come from a user, assume they aren't plain ASCII and assume you'll probably cut a word in half unless you explicitly prevent it.
📋 Practical Task
Building a Robust User-Handle Formatter
You've been asked to create a function that cleans up raw user input to create a "clean" social media handle. The handle must be lowercase, have no trailing or leading whitespace, and cannot be longer than 15 characters. If the handle is truncated, it must not end in a hyphen or underscore (these should be trimmed off if they end up at the end of the string after truncation).
Requirements:
- Use
trim()to handle surrounding whitespace. - Use
mb_strtolower()for case normalization. - Use
mb_substr()to enforce the 15-character limit. - Use
rtrim()to remove any trailing underscores (_) or hyphens (-) that remain after the truncation.
Test your function with this input: " Super_Cool_Developer_2024 ".
Expected Output: "super_cool_dev" (or similar, depending on where the 15-char cut falls and the subsequent rtrim).
There are no comments for now.