0

Core string functions: strlen, substr, strpos, str_contains, str_starts_with, str_ends_with

Beginner5 min read·php-03-003

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
<?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