Question
How can I write two PHP functions that accept a string and determine whether it starts with a specified character or substring, or ends with a specified character or substring?
For example:
$str = "|apples}";
echo startsWith($str, '|'); // true
echo endsWith($str, '}'); // true
I want functions that work for both single characters and longer strings.
Short Answer
By the end of this page, you will understand how to check whether a string starts with or ends with a given value in PHP. You will learn how prefix and suffix checks work, how to write reusable helper functions, what built-in PHP options exist, and which beginner mistakes to avoid.
Concept
In PHP, checking whether a string starts with or ends with another string is a common string-processing task.
A string at the beginning is called a prefix. A string at the end is called a suffix.
For example, in this string:
$str = "|apples}";
"|"is the prefix"}"is the suffix
This matters in real programming because many tasks depend on matching text at the start or end of a string, such as:
- checking file extensions like
.jpg - validating URL paths like
/api/ - detecting comment markers or delimiters
- parsing formatted data
- validating user input
In modern PHP, the simplest built-in functions are:
str_starts_with()str_ends_with()
If you need compatibility with older PHP versions, you can write your own helper functions using substr() or strncmp().
The key idea is simple:
- To check the start, compare the first part of the string with the target text.
- To check the end, compare the last part of the string with the target text.
Mental Model
Think of a string like a word written on a strip of paper.
- A starts with check asks: "Does the left edge of the strip match this text?"
- An ends with check asks: "Does the right edge of the strip match this text?"
If the strip says:
|apples}
Then:
- the left edge is
| - the right edge is
}
You are not searching the whole strip. You are only checking one edge at a time.
Syntax and Examples
Modern PHP built-in functions
If you are using PHP 8 or later, use the built-in functions:
<?php
$str = "|apples}";
var_dump(str_starts_with($str, '|')); // true
var_dump(str_ends_with($str, '}')); // true
These are clear, readable, and recommended when available.
Writing your own helper functions
If you want custom functions or need support for older PHP versions, you can write them like this:
<?php
function startsWith(string $haystack, string $needle): bool
{
return substr($haystack, 0, strlen($needle)) === $needle;
}
function endsWith(string $haystack, string $needle): bool
{
return substr($haystack, -strlen($needle)) === $needle;
}
$str = "|apples}";
var_dump(startsWith($str, '|')); // true
var_dump(endsWith($str, '}')); // true
var_dump(startsWith($str, '|ap')); // true
var_dump(endsWith($str, 'es}')); // true
How this works
strlen($needle)gets the length of the text you want to match.substr($haystack, 0, strlen($needle))gets the first part of the string.substr($haystack, -strlen($needle))gets the last part of the string.===checks for an exact match.
Safer version for empty strings
A common edge case is when the search string is empty.
<?php
function startsWith(string $haystack, string $needle): bool
{
if ($needle === '') {
return true;
}
return substr($haystack, 0, strlen($needle)) === $needle;
}
function endsWith(string $haystack, string $needle): bool
{
if ($needle === '') {
return true;
}
return substr($haystack, -strlen($needle)) === $needle;
}
This matches the behavior of PHP's built-in functions: every string starts with and ends with an empty string.
Step by Step Execution
Consider this example:
<?php
function startsWith(string $haystack, string $needle): bool
{
return substr($haystack, 0, strlen($needle)) === $needle;
}
$str = "|apples}";
$result = startsWith($str, '|ap');
var_dump($result);
Step-by-step
-
$stris set to:|apples} -
startsWith($str, '|ap')is called. -
Inside the function:
$haystackis"|apples}"$needleis"|ap"
-
strlen($needle)returns3. -
substr($haystack, 0, 3)returns the first 3 characters:|ap -
The function compares:
"|ap" === "|ap" -
The result is
true. -
var_dump($result)outputs:
bool(true)
Example for endsWith
<?php
function endsWith(string $haystack, string $needle): bool
{
return substr($haystack, -strlen($needle)) === $needle;
}
$str = "|apples}";
$result = endsWith($str, 'es}');
var_dump($result);
What happens
strlen('es}')is3substr($str, -3)gets the last 3 characters- The last 3 characters are
es} "es}" === "es}"istrue
Real World Use Cases
Prefix and suffix checks appear in many practical PHP tasks.
File validation
$filename = "photo.jpg";
if (str_ends_with($filename, '.jpg')) {
echo "JPEG image";
}
Used for checking file types before processing uploads.
Route handling
$path = "/api/users";
if (str_starts_with($path, '/api/')) {
echo "API route";
}
Used in web applications to separate API routes from normal pages.
Parsing formatted text
$token = "#topic";
if (str_starts_with($token, '#')) {
echo "Hashtag detected";
}
Useful when parsing tags, commands, or special markers.
Template or delimiter checks
$value = "{name}";
if (str_starts_with($value, '{') && str_ends_with($value, '}')) {
echo "Looks like a placeholder";
}
Helpful in config files, templates, and simple parsers.
Real Codebase Usage
In real projects, developers usually use start/end checks in small reusable ways rather than rewriting the logic each time.
Common patterns
Validation
if (!str_ends_with($emailDomain, '.com')) {
throw new InvalidArgumentException('Invalid domain format');
}
Guard clauses
if (!str_starts_with($line, '[')) {
return;
}
This exits early when input does not match the expected format.
Sanitizing input
if (str_starts_with($path, '/')) {
$path = ltrim($path, '/');
}
Filtering arrays
$files = ['app.log', 'error.log', 'photo.jpg'];
$logs = array_filter($files, function ($file) {
return str_ends_with($file, '.log');
});
Configuration matching
$envKey = 'APP_DEBUG';
if (str_starts_with($envKey, 'APP_')) {
echo 'Application config';
}
In larger codebases, developers prefer:
- built-in functions when available
- helper methods for repeated logic
- exact comparisons with
=== - clear names like
$haystackand$needle
Common Mistakes
1. Using strpos() incorrectly
A very common mistake is this:
if (strpos($str, '|')) {
echo 'Starts with |';
}
This is wrong because strpos() returns 0 when the match is found at the beginning, and 0 is treated as false.
Correct version
if (strpos($str, '|') === 0) {
echo 'Starts with |';
}
2. Confusing "contains" with "starts with"
This checks whether the string contains the value anywhere, not specifically at the start:
strpos($str, 'app') !== false
For a prefix check, use:
str_starts_with($str, 'app')
or compare the first part manually.
3. Not handling empty needles
Broken logic can happen here:
function endsWith($haystack, $needle) {
return substr($haystack, -strlen($needle)) === $needle;
}
If $needle is an empty string, behavior may not be what you intended.
Safer version:
function endsWith($haystack, $needle) {
if ($needle === '') {
return true;
}
return substr($haystack, -strlen($needle)) === $needle;
}
4. Using loose comparison
Avoid:
return substr($haystack, 0, strlen($needle)) == $needle;
Prefer:
return substr($haystack, 0, strlen($needle)) === $needle;
Strict comparison avoids unexpected type conversion.
5. Forgetting case sensitivity
These checks are case-sensitive:
str_starts_with('Hello', 'he'); // false
If you want case-insensitive matching, normalize both strings:
str_starts_with(strtolower('Hello'), 'he'); // true
Comparisons
| Approach | Best for | Example | Notes |
|---|---|---|---|
str_starts_with() | Modern PHP prefix checks | str_starts_with($str, 'ab') | Available in PHP 8+ |
str_ends_with() | Modern PHP suffix checks | str_ends_with($str, '.jpg') | Available in PHP 8+ |
substr() comparison | Older PHP versions | substr($str, 0, 2) === 'ab' | Simple and readable |
strncmp() | Prefix checks with length control | strncmp($str, 'ab', 2) === 0 | Efficient for starts-with logic |
strpos() | Searching anywhere in a string | strpos($str, 'ab') | Not ideal for ends-with; easy to misuse |
str_starts_with() vs strpos()
str_starts_with()clearly expresses intent.strpos()is more general but easier to get wrong.- For beginners,
str_starts_with()is usually better.
substr() vs built-in functions
substr()works in older PHP versions.- Built-in functions are easier to read.
- Built-in functions reduce custom code and edge-case bugs.
strncmp() vs substr()
For starts-with checks, you may also see:
strncmp($haystack, $needle, strlen($needle)) === 0
This compares the beginning of the string directly without extracting a substring first. It is useful, but substr() is often easier for beginners to read.
Cheat Sheet
Prefix check
PHP 8+
str_starts_with($haystack, $needle)
Older PHP
substr($haystack, 0, strlen($needle)) === $needle
Suffix check
PHP 8+
str_ends_with($haystack, $needle)
Older PHP
substr($haystack, -strlen($needle)) === $needle
Reusable functions
function startsWith(string $haystack, string $needle): bool
{
if ($needle === '') return true;
return substr($haystack, 0, strlen($needle)) === $needle;
}
function endsWith(string $haystack, string $needle): bool
{
if ($needle === '') return true;
return substr($haystack, -strlen($needle)) === $needle;
}
Rules to remember
- Use
===for exact comparison. str_starts_with()andstr_ends_with()are case-sensitive.- Empty needle usually returns
true. strpos()is not the same as starts-with.- Suffix checks compare the end of the string only.
Quick examples
str_starts_with('hello', 'he'); // true
str_ends_with('hello', 'lo'); // true
str_starts_with('hello', 'He'); // false
str_ends_with('hello', 'LO'); // false
FAQ
How do I check if a string starts with a character in PHP?
Use str_starts_with($string, $char) in PHP 8+, or compare the first part of the string with substr() in older versions.
How do I check if a string ends with a character in PHP?
Use str_ends_with($string, $char) in PHP 8+, or compare the last part of the string with substr().
Can these functions check longer strings, not just one character?
Yes. They work with both single characters and longer substrings.
Are str_starts_with() and str_ends_with() case-sensitive?
Yes. "Hello" does not start with "he" unless you normalize case first.
What PHP version has str_starts_with() and str_ends_with()?
They were added in PHP 8.
Why is strpos() not always safe for starts-with checks?
Because a match at the beginning returns 0, and 0 can be mistaken for false if you do not use strict comparison.
What happens if the search string is empty?
PHP treats every string as starting with and ending with an empty string, so the result is true.
Should I write my own helper functions or use built-ins?
Use the built-in functions when available. Write helpers only if you need older PHP compatibility or want project-specific wrappers.
Mini Project
Description
Build a small PHP utility that validates simple text tokens. The utility should detect whether a token starts with a specific opening marker and ends with a specific closing marker. This mirrors real tasks like checking placeholders, wrappers, tags, or formatted values in configuration files and templates.
Goal
Create a PHP script that checks multiple strings and reports whether each one is wrapped correctly by a given prefix and suffix.
Requirements
- Write a
startsWith()function for prefix checking. - Write an
endsWith()function for suffix checking. - Test the functions with an array of sample strings.
- Print whether each string is correctly wrapped with
{and}.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.