Web アプリケーションを作っていると、フォームの入力値を整える、文字列の中に特定の語が含まれているか調べる、長すぎる文を切り詰める、といった「文字列をちょっと加工する」処理が頻繁に登場します。PHP にはこうした処理のための関数が標準で多数用意されており、覚えてしまえば自分でループを書くより圧倒的に速く・安全に書けます。この記事では、strlen() や substr()、strpos()、PHP 8.0 で追加された str_contains() などの基本的な文字列操作関数を、初心者の方にもわかるように実際に動くコードで解説します。日本語のようなマルチバイト文字を扱うときの注意点も、つまずきやすいポイントとあわせて取り上げます。
目次
まず押さえておきたい主要な関数
最初に、この記事で扱う関数の全体像を表で整理しておきます。それぞれの詳しい使い方は後の節で説明しますが、「こんな処理をしたいときはこの関数」という対応をここでつかんでおくと、あとの内容が頭に入りやすくなります。
| 関数 | 説明 | 例 |
|---|---|---|
strlen() | 文字列のバイト数を返す | strlen("abc") → 3 |
mb_strlen() | 文字列の文字数を返す(マルチバイト対応) | mb_strlen("あいう") → 3 |
substr() | 文字列の一部を取り出す | substr("Hello", 0, 2) → "He" |
mb_substr() | 文字列の一部を取り出す(マルチバイト対応) | mb_substr("あいう", 0, 2) → "あい" |
strpos() | 部分文字列が最初に現れる位置を返す | strpos("Hello", "l") → 2 |
str_contains() | 部分文字列を含むかを true/false で返す(PHP 8.0+) | str_contains("Hello", "ell") → true |
str_starts_with() | 指定した文字列で始まるかを判定する(PHP 8.0+) | str_starts_with("Hello", "He") → true |
str_ends_with() | 指定した文字列で終わるかを判定する(PHP 8.0+) | str_ends_with("Hello", "lo") → true |
strtolower() | すべて小文字に変換する | strtolower("ABC") → "abc" |
strtoupper() | すべて大文字に変換する | strtoupper("abc") → "ABC" |
ucfirst() | 先頭の 1 文字だけ大文字にする | ucfirst("hello") → "Hello" |
trim() | 前後の空白などを取り除く | trim(" ab ") → "ab" |
str_repeat() | 文字列を指定回数くり返す | str_repeat("ab", 3) → "ababab" |
文字列の長さを数える:strlen と mb_strlen
文字列の長さを取得する最も基本的な関数が strlen() です。引数に文字列を渡すと、その長さを整数で返します。ただしここで気をつけたいのは、strlen() が返すのは「文字数」ではなく「バイト数」だという点です。アルファベットや数字なら 1 文字 = 1 バイトなので一致しますが、日本語のようなマルチバイト文字では結果がずれます。
<?php
// 半角英字は 1 文字 = 1 バイトなので一致する
echo strlen("Hello"); // 5
// 日本語(UTF-8)は 1 文字 3 バイト → バイト数が返る
echo strlen("こんにちは"); // 15
// 文字数を数えたいときは mb_strlen を使う
echo mb_strlen("こんにちは"); // 5
UTF-8 では、ひらがなや漢字 1 文字はおおむね 3 バイトで表現されます。そのため「こんにちは」は 5 文字でも、strlen() では 15 という値になります。入力された文字数を制限したい、画面に表示する文字数を数えたい、といった「人間が見たままの文字数」を扱いたい場面では、必ず mb_strlen()(マルチバイト文字列用の関数)を使うようにしましょう。mb_ で始まる関数群は、文字エンコーディングを意識して 1 文字単位で正しく処理してくれます。
文字列の一部を取り出す:substr と mb_substr
文字列の一部分だけを切り出したいときは substr() を使います。構文は substr(string $string, int $offset, ?int $length = null): string で、第 2 引数の $offset に開始位置(先頭は 0)、第 3 引数の $length に取り出す長さを指定します。$length を省略すると、開始位置から末尾までを取り出します。
<?php
$str = "Hello, World";
// 先頭(0 番目)から 5 文字を取り出す
echo substr($str, 0, 5); // Hello
// 7 番目から末尾まで(length 省略)
echo substr($str, 7); // World
// offset に負の値を渡すと末尾から数えた位置になる
echo substr($str, -5); // World
覚えておくと便利なのが、開始位置に負の値を渡せる点です。substr($str, -5) のように書くと、文字列の末尾から数えて 5 文字目を開始位置とします。ファイルの拡張子だけを取り出したいときなど、末尾を起点に処理したい場面で役立ちます。
日本語を切り出すなら mb_substr
substr() もバイト単位で動作するため、日本語をそのまま切り出すと文字の途中で分割され、文字化けの原因になります。次の例を見てください。
<?php
$str = "こんにちは";
// substr はバイト単位 → 3 バイト = 1 文字分しか取れない
echo substr($str, 0, 3); // こ
// mb_substr なら「文字数」で正しく取り出せる
echo mb_substr($str, 0, 3); // こんに
substr($str, 0, 3) は「先頭から 3 バイト」を取り出すため、3 バイトでちょうど 1 文字分の「こ」だけが返ります。日本語のように 1 文字が複数バイトになる文字列を扱うときは、mb_substr() を使えば文字数の単位で安全に切り出せます。一覧画面で本文を一定の文字数だけ表示する、といった処理では mb_substr() が基本になります。
特定の文字がどこにあるか調べる:strpos
文字列の中で、ある部分文字列が最初に現れる位置を知りたいときは strpos() を使います。構文は strpos(string $haystack, string $needle, int $offset = 0): int|false で、第 1 引数に「探される側の文字列」、第 2 引数に「探したい文字列」を渡します。見つかった場合はその開始位置(先頭は 0)を整数で、見つからなかった場合は false を返します。
<?php
$str = "Hello, World";
// "World" は 7 番目から始まる
var_dump(strpos($str, "World")); // int(7)
// 先頭にある場合は 0 が返る
var_dump(strpos($str, "Hello")); // int(0)
// 見つからないときは false
var_dump(strpos($str, "PHP")); // bool(false)
日本語を含む文字列で「何文字目にあるか」を正しく求めたい場合は、ここでも mb_strpos() を使います。strpos() はバイト位置を返すため、日本語では位置の数値がずれてしまうからです。
strpos の 0 と false を取り違えない
strpos() でとくに初心者がはまりやすいのが、戻り値の 0 と false の扱いです。先ほどの例のとおり、探したい文字列が先頭にあると strpos() は位置 0 を返します。一方、見つからなかったときは false を返します。PHP ではこの 2 つが条件式の中で同じ「偽」として扱われてしまうため、書き方を誤ると意図しない動作になります。
== や if だけで判定すると先頭一致を見逃す
次のコードは「文字列が見つかったかどうか」を判定しているつもりですが、正しく動きません。
<?php
$str = "Hello, World";
// strpos が 0 を返すと、0 は「偽」とみなされてしまう
if (strpos($str, "Hello")) {
echo "見つかりました";
} else {
echo "見つかりませんでした"; // 実際にはこちらが表示される
}
“Hello” は文字列の先頭にあるので strpos() は 0 を返しますが、if (0) は偽と判定されるため、「見つかりませんでした」と表示されてしまいます。これは「見つからなかった場合の false」と「先頭で見つかった場合の 0」を if が区別できないために起こる、典型的なバグです。
=== false で型まで含めて比較する
この問題を避けるには、値と型の両方を比較する厳密比較演算子 ===(または !==)を使い、戻り値が false かどうかをはっきり判定します。0 は整数、false は真偽値なので、=== なら両者をきちんと区別できます。
<?php
$str = "Hello, World";
// 「false ではない」=見つかった、と判定する
if (strpos($str, "Hello") !== false) {
echo "見つかりました"; // こちらが正しく表示される
} else {
echo "見つかりませんでした";
}
このように、strpos() の結果を「含まれているか」の判定に使うときは、必ず === false や !== false で比較するのが鉄則です。位置そのものが必要なら戻り値を変数に入れて使い、含むか否かだけを知りたいなら次に紹介する関数を使うと、こうした取り違えを根本から避けられます。
含むかどうかを素直に判定する:str_contains(PHP 8.0+)
PHP 8.0 からは、文字列の中に部分文字列が含まれているかを直接 true / false で返す str_contains() が追加されました。strpos() のように位置を返すわけではないので、先ほどの 0 と false の取り違えを気にする必要がなく、コードの意図もそのまま読み取れます。
<?php
$str = "Hello, World";
// 含まれていれば true、含まれていなければ false
var_dump(str_contains($str, "World")); // bool(true)
var_dump(str_contains($str, "PHP")); // bool(false)
// strpos のような === false の判定が不要になる
if (str_contains($str, "Hello")) {
echo "見つかりました"; // 先頭一致でも正しく動く
}
「含むかどうかだけを知りたい」という用途であれば、str_contains() を使うのがいまの PHP では最もシンプルで安全です。あわせて、特定の文字列で始まるかを調べる str_starts_with()、終わるかを調べる str_ends_with() も同じく PHP 8.0 で追加されました。URL の先頭が https:// かを確認したり、ファイル名が .png で終わるかを判定したりといった処理が、ひと目で読めるコードになります。
<?php
$url = "https://example.com/image.png";
// 先頭が https:// かどうか
var_dump(str_starts_with($url, "https://")); // bool(true)
// 末尾が .png かどうか
var_dump(str_ends_with($url, ".png")); // bool(true)
大文字・小文字の変換と前後の空白除去
大文字・小文字をそろえる処理もよく使います。すべて小文字にするには strtolower()、すべて大文字にするには strtoupper()、先頭の 1 文字だけを大文字にするには ucfirst() を使います。メールアドレスの大文字・小文字を統一して比較したいときなどに便利です。
<?php
echo strtolower("Hello WORLD"); // hello world
echo strtoupper("Hello world"); // HELLO WORLD
echo ucfirst("hello"); // Hello
フォームから受け取った値には、前後に余計な空白が入っていることがよくあります。trim() を使うと、文字列の前後にある空白や改行、タブといった空白文字をまとめて取り除けます。前側だけを処理する ltrim()、後ろ側だけを処理する rtrim() もあります。
<?php
$input = " user@example.com ";
// 前後の空白を取り除いてから使う
$email = trim($input);
echo "[" . $email . "]"; // [user@example.com]
同じ文字列をくり返す:str_repeat
同じ文字列を指定した回数だけくり返したいときは str_repeat() が便利です。第 1 引数にくり返す文字列、第 2 引数に回数を渡します。区切り線を引いたり、桁数をそろえるための文字を作ったりするときに使えます。
<?php
// "ab" を 3 回くり返す
echo str_repeat("ab", 3); // ababab
// 区切り線として使う
echo str_repeat("-", 20); // --------------------
まとめ
PHP の文字列操作は、用途に合った関数を選べば短く安全に書けます。長さを数えるなら strlen()、一部を取り出すなら substr()、含まれるかや位置を調べるなら strpos() や str_contains() が基本になります。とくに strpos() は、見つからないときの false と先頭一致の 0 を区別するために === false で判定すること、含むかどうかだけ知りたいときは str_contains() を使うことを覚えておきましょう。そして日本語などのマルチバイト文字を扱う場面では、strlen() や substr() がバイト単位で動くことに注意し、文字数の単位で正しく処理できる mb_strlen() や mb_substr() を選ぶのがポイントです。まずは手元の環境でひとつずつ実行して、戻り値の型や値を確かめてみてください。