しばしばどこかしらから得た文字列を結合してファイルパスや URL を構築する時があります。この時、文字列結合関数である implode 関数を使うなどして結合元となる文字列をそのまま結合すると、結合前の時点で区切り文字を含んでいた場合、処理結果に区切り文字が複数重なって現れることになります。これは例えば次です。
PHP: implode – Manual
$root = 'https://example.com/'; // Web サイトのルートページの URL $path = '/manual/ja/example'; // ある Web ページのルート相対パス $url = implode('/', [$root, $path]); // https://example.com//manual/ja/example となり /// と三重になる
流石にこの様な直書きの時に失敗することはなかなかないでしょうが、様々なところを経由してきた結果の文字列の結合であったりすると起こりやすいです。
また、区切り文字を含んでいるものとして取り扱った対象に実は区切り文字が存在していなかった、という時は致命的エラーの原因になり得ます(区切り文字多重化の問題は文字列を渡すエンジンがよしなにしてくれる時もあります)。
$root = 'https://example.com'; // Web サイトのプロトコルとホスト $path = 'manual/ja/example'; // ある Web ページのルートから見た場合の相対パス $url = implode('', [$root, $path]); // https://example.commanual/ja/example となり、誤ったホストへ通信することになる
PHP 上でこれを防ぐ時に便利なのが trim 関数です。
PHP: trim – Manual
PHP: ltrim – Manual
PHP: rtrim – Manual
PHP の trim 関数は文字列の両端から削除したい文字のリストに当てはまる文字を可能な限り削除する関数です。ltrim 関数は左端のみ、rtrim 関数は右端のみに trim 関数同様の処理をする関数です。もっともよくある使い方は他言語の色々な trim 同様に両端の空白を削除する使い方でしょう。
$trimed = trim(' abc '); var_dump($trimed); // string(3) "abc"
trim 関数は第二引数で削除したい文字のリストを指定できます。デフォルトでは英語圏における空白文字があてられています(上記例の様に trim 関数を呼び出す方針では全角スペースを削除できません)。これを利用して結合対象の文字列の区切り文字を一律で存在しない状態に変換することによって見た目が良く、問題も起きない文字列結合を行えます。これは次の様に書けます。
<?php $root = 'https://example.com/'; $path = '/manual/ja/example'; $separator = '/'; $trimmed = array_map( static fn(string $str) => trim($str, $separator), [$root, $path] ); $url = implode('/', $trimmed); echo $url; // https://example.com/manual/ja/example となり、正常。
implode 関数を使うまでもない時は次の様に書けます。
<?php $root = 'https://example.com/'; $path = '/manual/ja/example'; $sep = '/'; $url = rtrim($root, $sep) . $sep . ltrim($path, $sep); echo $url; // https://example.com/manual/ja/example となり、正常。
区切り文字の重複を危険視するのみならば、結合後の両端に触らない様に最初の結合対象文字列は rtrim 関数、最後の結合対象文字列は ltrim 関数、とするのも良いです。
こんな感じで trim 関数を使うといい感じに区切り文字の重複を省いた文字列結合ができます。