Core string functions: strlen, substr, strpos, str_contains, str_starts_with, str_ends_with
Concept
PHP 8's string functions split into two generations: the classic byte-string functions that have existed since PHP 3, and the new semantic functions added in PHP 8.0 (str_contains, str_starts_with, str_ends_with) that finally made common string checks readable and reliable.
strlen returns the byte length of a string. O(1) because zend_string stores the length pre-computed in its struct — no scanning required.
substr($str, $start, $length) returns a portion of a string. Negative $start counts from the end. Negative $length removes that many characters from the end. Returns false if $start is beyond the string length (PHP < 8.0); returns "" in PHP 8+.
strpos($haystack, $needle, $offset) returns the byte position of the first occurrence of $needle, or false if not found. Always use strict comparison (!== false) — position 0 is falsy. stripos is the case-insensitive variant.
str_contains (PHP 8.0) returns true if $needle is found anywhere in $haystack. Unlike strpos, no !== false dance needed. str_starts_with and str_ends_with check the beginning and end respectively. All three accept an empty string as $needle and always return true in that case.
Code Example
<?php
declare(strict_types=1);
$str = 'The quick brown fox jumps over the lazy dog';
// strlen — byte length
echo strlen($str); // 43
// substr — extract portions
echo substr($str, 4, 5); // "quick"
echo substr($str, -3); // "dog"
echo substr($str, 0, -4); // removes last 4 chars
// strpos — find position (watch out for position 0!)
$pos = strpos($str, 'The');
var_dump($pos); // int(0)
var_dump($pos == false); // true! — BUG: use !== false
var_dump($pos !== false); // true — correct check
// With offset — find second occurrence
$html = '<b>bold</b> and <b>more bold</b>';
$first = strpos($html, '<b>'); // 0
$second = strpos($html, '<b>', $first + 1); // 17
// PHP 8.0 semantic functions — clean and reliable
$email = 'user@example.com';
if (str_contains($email, '@')) {
echo "Has @ symbol\n";
}
if (str_starts_with($email, 'user')) {
echo "Starts with 'user'\n";
}
if (str_ends_with($email, '.com')) {
echo "Is .com domain\n";
}
// substr_count — count occurrences
echo substr_count('hello world hello', 'hello'); // 2
// substr_replace — replace a portion by position
$card = '4111111111111111';
echo substr_replace($card, str_repeat('*', 12), 0, 12); // ****1111