文字列

string は、文字が連結されたものです。PHP では、 文字は 1 バイトと同じです。つまり、256 個の異なる文字を使用可能です。 これは、PHP が Unicode をネイティブにサポートしていないことも意味します。 文字列型の詳細を参照ください。

注意: 32bit ビルドでは、 文字列の最大長は 2GB (2147483647 バイト) です。

構文

文字列リテラルは、4 つの異なる方法で指定することが可能です。

引用符

文字列を指定する最も簡単な方法は、引用符 (文字 ') で括ることです。

引用符をリテラルとして指定するには、バックスラッシュ (\) でエスケープする必要があります。 バックスラッシュをリテラルとして指定するには、二重 (\\) にします。 それ以外の場面で登場するバックスラッシュは、すべてバックスラッシュそのものとして扱われます。 つまり、\r\n といったおなじみのエスケープシーケンスを書いても特別な効果は得られず、 書いたままの形式で出力されます。

注意: ダブルクォート 構文や heredoc 構文とは異なり、 変数と特殊文字のエスケープシーケンスは、 引用符 (シングルクオート) で括られた文字列にある場合には展開されません

<?php
echo 'this is a simple string';

echo 
'You can also have embedded newlines in 
strings this way as it is
okay to do'
;

// 出力: Arnold once said: "I'll be back"
echo 'Arnold once said: "I\'ll be back"';

// 出力: You deleted C:\*.*?
echo 'You deleted C:\\*.*?';

// 出力: You deleted C:\*.*?
echo 'You deleted C:\*.*?';

// 出力: This will not expand: \n a newline
echo 'This will not expand: \n a newline';

// 出力: Variables do not $expand $either
echo 'Variables do not $expand $either';
?>

二重引用符

文字列が二重引用符 (") で括られた場合、 PHP は、以下のエスケープシーケンスを特殊な文字として解釈します。

エスケープされた文字
記述 意味
\n ラインフィード (LF またはアスキーの 0x0A (10))
\r キャリッジリターン (CR またはアスキーの 0x0D (13))
\t 水平タブ (HT またはアスキーの 0x09 (9))
\v 垂直タブ (VT またはアスキーの 0x0B (11))
\e エスケープ (ESC あるいはアスキーの 0x1B (27))
\f フォームフィード (FF またはアスキーの 0x0C (12))
\\ バックスラッシュ
\$ ドル記号
\" 二重引用符
\[0-7]{1,3} 正規表現にマッチする文字シーケンスは、8 進数表記の 1 文字です。 1 バイトに収まらない部分は、何もメッセージを出さずにオーバーフローします (そのため、"\400" === "\000" となります)。
\x[0-9A-Fa-f]{1,2} 正規表現にマッチする文字シーケンスは、16 進数表記の 1 文字です。
\u{[0-9A-Fa-f]+} 正規表現にマッチする文字シーケンスは、Unicode のコードポイントです。 そのコードポイントの UTF-8 表現を文字列として出力します。

繰り返しますが、この他の文字をエスケープしようとした場合には、 バックスラッシュも出力されます!

しかし、二重引用符で括られた文字列で最も重要なのは、 変数名が展開されるところです。詳細は、文字列のパースを参照ください。

ヒアドキュメント

文字列を区切る別の方法としてヒアドキュメント構文 ("<<<") があります。この場合、ある ID (と、それに続けて改行文字) を <<< の後に指定し、文字列を置いた後で、同じ ID を括りを閉じるために置きます。

終端 ID は、その行の最初のカラムから始める必要があります。 使用するラベルは、PHP の他のラベルと同様の命名規則に従う必要があります。 つまり、英数字およびアンダースコアのみを含み、 数字でない文字またはアンダースコアで始まる必要があります。

警告

非常に重要なことですが、終端 ID がある行には、セミコロン (;) 以外の他の文字が含まれていてはならないことに注意しましょう。 これは、特に ID はインデントしてはならないということ、 セミコロンの前に空白やタブを付けてはいけないことを意味します。 終端 ID の前の最初の文字は、使用するオペレーティングシステムで定義された 改行である必要があることにも注意を要します。 これは、UNIX システムでは macOS を含め \n となります。 最後の区切り文字の後にもまた、改行を入れる必要があります。

この規則が破られて終端 ID が "clean" でない場合、 終端 ID と認識されず、PHP はさらに終端 ID を探し続けます。 適当な終了 ID がみつからない場合、 スクリプトの最終行でパースエラーが発生します。

例1 間違った例

<?php
class foo {
    public 
$bar = <<<EOT
bar
    EOT;
}
// 識別子はインデントしてはいけません
?>

例2 有効な例

<?php
class foo {
    public 
$bar = <<<EOT
bar
EOT;
}
?>

変数を含んでいるヒアドキュメントは、クラスのプロパティの初期化に用いることはできません。

ヒアドキュメントは二重引用符を使用しませんが、 二重引用符で括られた文字列と全く同様に動作します。 しかし、この場合でも上記のリストでエスケープされたコードを使用することも可能です。 変数は展開されますが、文字列の場合と同様に ヒアドキュメントの内部で複雑な変数を表わす場合には注意が必要です。

例3 ヒアドキュメントで文字列を括る例

<?php
$str 
= <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;

/* 変数を使用するより複雑な例 */
class foo
{
    var 
$foo;
    var 
$bar;

    function 
__construct()
    {
        
$this->foo 'Foo';
        
$this->bar = array('Bar1''Bar2''Bar3');
    }
}

$foo = new foo();
$name 'MyName';

echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some 
{$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;
?>

上の例の出力は以下となります。

My name is "MyName". I am printing some Foo.
Now, I am printing some Bar2.
This should print a capital 'A': A

ヒアドキュメント構文を用いて、 関数の引数にデータを渡すこともできます。

例4 ヒアドキュメントを引数に使用する例

<?php
var_dump
(array(<<<EOD
foobar!
EOD
));
?>

静的な変数やクラスのプロパティ/定数は、 ヒアドキュメント構文で初期化することができます。

例5 ヒアドキュメントを用いた静的な値の初期化

<?php
// 静的変数
function foo()
{
    static 
$bar = <<<LABEL
Nothing in here...
LABEL;
}

// クラスのプロパティ/定数
class foo
{
    const 
BAR = <<<FOOBAR
Constant example
FOOBAR;

    public 
$baz = <<<FOOBAR
Property example
FOOBAR;
}
?>

ヒアドキュメントの宣言をダブルクォートで囲むこともできます。

例6 ヒアドキュメントでのダブルクォート

<?php
echo <<<"FOOBAR"
Hello World!
FOOBAR;
?>

Nowdoc

Nowdoc はヒアドキュメントと似ていますが、 ヒアドキュメントがダブルクォートで囲んだ文字列として扱われるのに対して、 Nowdoc はシングルクォートで囲んだ文字列として扱われます。 Nowdoc の使用方法はヒアドキュメントとほぼ同じですが、 その中身について パース処理を行いません。 PHP のコードや大量のテキストを埋め込む際に、 エスケープが不要になるので便利です。この機能は、SGML の <![CDATA[ ]]> (ブロック内のテキストをパースしないことを宣言する) と同じようなものです。

Nowdoc の書き方は、ヒアドキュメントと同じように <<< を使用します。 しかし、その後に続く識別子をシングルクォートで囲んで <<<'EOT' のようにします。 ヒアドキュメントの識別子に関する決まりがすべて Nowdoc の識別子にも当てはまります。特に終了識別子の書き方に関する決まりに注意しましょう。

例7 Nowdoc による文字列のクォートの例

<?php
echo <<<'EOD'
Example of string spanning multiple lines
using nowdoc syntax. Backslashes are always treated literally,
e.g. \\ and \'.
EOD;

上の例の出力は以下となります。

Example of string spanning multiple lines
using nowdoc syntax. Backslashes are always treated literally,
e.g. \\ and \'.

例8 Nowdoc string quoting example with variables

<?php
/* 変数を使った、より複雑な例 */
class foo
{
    public 
$foo;
    public 
$bar;

    function 
__construct()
    {
        
$this->foo 'Foo';
        
$this->bar = array('Bar1''Bar2''Bar3');
    }
}

$foo = new foo();
$name 'MyName';

echo <<<'EOT'
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should not print a capital 'A': \x41
EOT;
?>

上の例の出力は以下となります。

My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should not print a capital 'A': \x41

例9 静的データの例

<?php
class foo {
    public 
$bar = <<<'EOT'
bar
EOT;
}
?>

変数のパース

スクリプトが二重引用符で括られるかヒアドキュメントで指定された場合、 その中の変数はパースされます。

構文の型には、単純な構文と 複雑な 構文の 2 種類があります。簡単な構文は、最も一般的で便利です。 この構文では、変数、配列値やオブジェクトのプロパティをパースすることが可能です。

複雑な構文は、式を波括弧で括ることにより認識されます。

簡単な構文

ドル記号 ($) を見付けると、 パーサは、有効な変数名を形成することが可能な最長のトークンを取得します。 変数名の終りを明示的に指定したい場合は、変数名を波括弧で括ってください。

<?php
$juice 
"apple";

echo 
"He drank some $juice juice.".PHP_EOL;
// 動作しません。"s" は、変数名として有効な文字ですが、実際の変数名は $juice です。
echo "He drank some juice made of $juices.";
// 動作します。波括弧で囲むことで、どこまでが変数名かを明示しているからです。
echo "He drank some juice made of ${juice}s.";
?>

上の例の出力は以下となります。

He drank some apple juice.
He drank some juice made of .
He drank some juice made of apples.

同様に、配列添字とオブジェクトのプロパティをパースすることも可能です。 配列添字の場合、閉じ角括弧 (]) は添字の終りを意味します。 シンプルな変数の場合と同じ規則が、オブジェクトのプロパティに対しても適用されます。

例10 簡単な構文の例

<?php
$juices 
= array("apple""orange""koolaid1" => "purple");

echo 
"He drank some $juices[0] juice.".PHP_EOL;
echo 
"He drank some $juices[1] juice.".PHP_EOL;
echo 
"He drank some $juices[koolaid1] juice.".PHP_EOL;

class 
people {
    public 
$john "John Smith";
    public 
$jane "Jane Smith";
    public 
$robert "Robert Paulsen";
    
    public 
$smith "Smith";
}

$people = new people();

echo 
"$people->john drank some $juices[0] juice.".PHP_EOL;
echo 
"$people->john then said hello to $people->jane.".PHP_EOL;
echo 
"$people->john's wife greeted $people->robert.".PHP_EOL;
echo 
"$people->robert greeted the two $people->smiths."// 動作しません
?>

上の例の出力は以下となります。

He drank some apple juice.
He drank some orange juice.
He drank some purple juice.
John Smith drank some apple juice.
John Smith then said hello to Jane Smith.
John Smith's wife greeted Robert Paulsen.
Robert Paulsen greeted the two .

PHP 7.1.0 以降では、 負の 数値インデックスもサポートされました。

例11 負の数値インデックス

<?php
$string 
'string';
echo 
"The character at index -2 is $string[-2]."PHP_EOL;
$string[-3] = 'o';
echo 
"Changing the character at index -3 to o gives $string."PHP_EOL;
?>

上の例の出力は以下となります。

The character at index -2 is n.
Changing the character at index -3 to o gives strong.

より複雑な場合は、複雑な構文を使用する必要があります。

複雑な (波括弧) 構文

この構文が「複雑(complex)な構文」と呼ばれているのは、 構文が複雑であるからではなく、 この方法では複雑な式を含めることができるからです。

どんなスカラー変数、配列の要素あるいはオブジェクトのプロパティの文字列表現であっても この構文で含めることができます。 文字列の外側に置く場合と同様に式を書き、これを { と } の間に含めてください。'{' はエスケープすることができないため、 この構文は $ が { のすぐ後に続く場合にのみ認識されます (リテラル "{$" を指定するには、"{\$" を使用してください)。 以下のいくつかの例を見ると理解しやすくなるでしょう。

<?php
// すべてのエラーを表示します
error_reporting(E_ALL);

$great 'fantastic';

// うまく動作しません。出力: This is { fantastic}
echo "This is { $great}";

// うまく動作します。出力: This is fantastic
echo "This is {$great}";

// 動作します
echo "This square is {$square->width}00 centimeters broad."


// 動作します。クォートしたキーを使う場合は、波括弧構文を使わなければなりません
echo "This works: {$arr['key']}";


// 動作します
echo "This works: {$arr[4][3]}";

// これが動作しない理由は、文字列の外で $foo[bar]
// が動作しない理由と同じです。
// 言い換えると、これは動作するともいえます。しかし、
// PHP はまず最初に foo という名前の定数を探すため、
// E_NOTICE レベルのエラー(未定義の定数) となります。
echo "This is wrong: {$arr[foo][3]}"

// 動作します。多次元配列を使用する際は、
// 文字列の中では必ず配列を波括弧で囲むようにします。
echo "This works: {$arr['foo'][3]}";

// 動作します
echo "This works: " $arr['foo'][3];

echo 
"You can even write {$obj->values[3]->name}";

echo 
"This is the value of the var named $name{${$name}}";

echo 
"This is the value of the var named by the return value of getName(): {${getName()}}";

echo 
"This is the value of the var named by the return value of \$object->getName(): {${$object->getName()}}";

// 動作しません。出力: This is the return value of getName(): {getName()}
echo "This is the return value of getName(): {getName()}";
?>

文字列内で、変数を使ってクラスのプロパティにアクセスすることもできます。 このような構文を使います。

<?php
class foo {
    var 
$bar 'I am bar.';
}

$foo = new foo();
$bar 'bar';
$baz = array('foo''bar''baz''quux');
echo 
"{$foo->$bar}\n";
echo 
"{$foo->{$baz[1]}}\n";
?>

上の例の出力は以下となります。

I am bar.
I am bar.

注意:

{$} の内部における 関数やメソッドのコール、静的クラス変数、クラス定数からアクセスする値は、 文字列が定義されたスコープにおける変数名として解釈します。 ひとつの波括弧 ({}) では、 関数やメソッドの返り値、クラス定数や静的クラス変数の値にはアクセスできません。

<?php
// すべてのエラーを表示します
error_reporting(E_ALL);

class 
beers {
    const 
softdrink 'rootbeer';
    public static 
$ale 'ipa';
}

$rootbeer 'A & W';
$ipa 'Alexander Keith\'s';

// これは動作し、出力は I'd like an A & W となります
echo "I'd like an {${beers::softdrink}}\n";

// これも動作し、出力は I'd like an Alexander Keith's となります
echo "I'd like an {${beers::$ale}}\n";
?>

文字列への文字単位のアクセスと修正

$str[42] のように、 角括弧を使用してゼロから始まるオフセットを指定すると、 文字列内の任意の文字にアクセスし、修正することが可能です。 つまり、文字列を文字の配列として考えるわけです。 複数の文字を取り出したり変更したりしたいときは、関数 substr() および substr_replace() が使えます。

注意: PHP 7.1.0 以降では、負の文字列オフセットにも対応するようになりました。 これは、文字列の末尾からのオフセットを表します。 以前のバージョンでは、負のオフセットで読み込もうとすると E_NOTICE が発生し (空文字列を返します)、負のオフセットで書き込もうとすると E_WARNING が発生していました (文字列には何も手が加えられません)。

注意: PHP 8.0.0 より前のバージョンでは、 $str{42} のように波括弧を使用してアクセスすることもできました。 この文法は PHP 7.4.0 以降は非推奨になり、 PHP 8.0.0 以降はサポートされなくなっています。

警告

範囲外のオフセットに書き込んだ場合は、空いた部分に空白文字が埋められます。 整数型以外の型は整数型に変換されます。 無効なオフセット形式を指定した場合は E_WARNING を発行します。 文字列を代入した場合は最初の文字だけを使用します。 PHP 7.1.0 以降では、空の文字列を代入すると fatal エラーが発生するようになりました。 これまでのバージョンでは、NULL バイトが代入されていました。

警告

内部的には、PHP の文字列はバイト配列です。 そのため、角括弧を使った配列形式での文字列へのアクセスは、 マルチバイト対応ではありません。この方法は、 ISO-8859-1 のようなシングルバイトエンコーディングの文字列に対してだけしか使えません。

注意: PHP 7.1.0 以降では、空の文字列に空のインデックス演算子を適用すると fatal エラーが発生するようになりました。 これまでのバージョンではエラーにならず、空の文字列が配列に変換されていました。

例12 文字列の例

<?php
// 文字列の最初の文字を取得します
$str 'This is a test.';
$first $str[0];

// 文字列の 3 番目の文字を取得します
$third $str[2];

// 文字列の最後の文字を取得します
$str 'This is still a test.';
$last $str[strlen($str)-1]; 

// 文字列の最後の文字を変更します
$str 'Look at the sea';
$str[strlen($str)-1] = 'e';

?>

文字列のオフセットは整数あるいは整数と見なせる文字列に限られます。 それ以外の場合は警告が発生します。

例13 不正な文字列のオフセットの例

<?php
$str 
'abc';

var_dump($str['1']);
var_dump(isset($str['1']));

var_dump($str['1.0']);
var_dump(isset($str['1.0']));

var_dump($str['x']);
var_dump(isset($str['x']));

var_dump($str['1x']);
var_dump(isset($str['1x']));
?>

上の例の出力は以下となります。

string(1) "b"
bool(true)

Warning: Illegal string offset '1.0' in /tmp/t.php on line 7
string(1) "b"
bool(false)

Warning: Illegal string offset 'x' in /tmp/t.php on line 9
string(1) "a"
bool(false)
string(1) "b"
bool(false)

注意:

その他の型の変数 (配列や、適切なインターフェイスを実装したオブジェクトを除く) に対して []{} でアクセスすると、何もメッセージを出さずに単に null を返します。

注意:

文字列リテラル内の文字に対して []{} でアクセスすることができます。

注意:

文字列リテラル内の文字に対して、 {} を使ってアクセスする機能は、 PHP 7.4 で非推奨になり、PHP 8.0 で削除されました。

便利な関数および演算子

文字列は、'.' (ドット) 結合演算子で結合することが可能です。'+' (加算) 演算子はこの例では出てこないことに注意してください。詳細については 文字列演算子 を参照ください。

文字列の修正を行う場合には、便利な関数がたくさん用意されています。

一般的な関数については、文字列関数の節 を参照ください。高度な検索/置換を行う関数については Perl 互換の正規表現関数 を参照ください。

URL 文字列用関数や文字列の暗号化/ 復号用の関数 (Sodium および Hash) もあります。

最後に、探しているものがまだ見付からない場合には、 文字型の関数も参照ください。

文字列への変換

(string) キャストや strval() 関数を使って変数を文字列へ変換することができます。 文字列型を必要とする式のスコープにおいて、文字列への変換は自動的に行われます。 echoprint 関数を使うとき、 あるいは可変変数を文字列を比較するときにこの自動変換が行われます。 マニュアルの型の相互変換 の項を読むとわかりやすいでしょう。 settype()も参照してください。

booltrue は文字列の "1" に、 false"" (空文字列) に変換されます。 これにより boolean と文字列の値を相互に変換することができます。

int (整数) や浮動小数点数 (float) は その数値の数字として文字列に変換されます (指数の表記や浮動小数点数を含めて)。 浮動小数点数は、指数表記 (4.1E+6) を使用して変換されます。

注意:

PHP 8.0.0 以降では、小数点を表す文字は常に . です。 それより前のバージョンでは、 スクリプトのロケール (LC_NUMERIC カテゴリ) によって決まります。 setlocale() を参照ください。

配列は常に "Array" という文字列に変換されるので、 array の中を見るために echoprint を使ってダンプさせることはできません。 一つの要素を見るためには、echo $arr['foo'] のようにしてください。内容の全てをダンプ/見るためには以降の TIP をご覧ください。

objectstring へ変換するには、 マジック・メソッド __toString を使用してください。

リソースは常に "Resource id #1" という文字列に変換されます。1 は実行中の PHP によって割り当てられる resource の番号です。 この文字列の構造に依存したコードを書いてはいけません (この構造は変わる可能性があります) が、スクリプトの実行中 (ウェブのリクエストや CLI プロセスの処理中) は、指定したリソースに対してこの文字列が一意に割り当てられることが保証されます。 他のリソースで同じ文字列が再利用されることはありません。 リソースの型を知るためには get_resource_type() を使用してください。

null は常に空文字列に変換されます。

以上に述べたように、配列、オブジェクト、リソースをプリントアウトしても その値に関する有益な情報を得られるわけではありません。 デバッグのために値を出力するのによりよい方法が知りたければ、 print_r()var_dump() を参照ください。

PHP 変数を恒久的に保存するための文字列に変換することもできます。 この方法はシリアライゼーションと呼ばれ、 serialize() 関数によって実現できます。

文字列型の詳細

PHP における文字列型は、バイトの配列と整数値 (バッファ長) で実装されています。 バイト列を文字列に変換する方法については何の情報も持っておらず、完全にプログラマ任せとなっています。 文字列を構成する値には何の制限もありません。特に気をつけるべきなのは、 値 0 のバイト (いわゆる “NUL バイト”) を文字列内のどの部分にでも使えるという点です (しかし、このマニュアル上で「バイナリセーフではない」とされている一部の関数では、 受け取った文字列をライブラリに渡すときに NUL バイト以降を無視することがあります)。

PHP の文字列型の正体を知ってしまえば、なぜ PHP には「バイト型」が存在しないのかもわかります。 つまり、文字列型がその役割を受け持っているのです。テキスト以外のデータ、 たとえばネットワークソケットから読み込んだ任意のデータを返す関数も、 文字列で値を返します。

PHP が文字列に対して特定のエンコーディングを強制しないのなら、 いったいどのようにして文字列リテラルをエンコードしているのでしょう? たとえば、文字列 "á" と同等なのは "\xE1" (ISO-8859-1)、 "\xC3\xA1" (UTF-8, C form)、 "\x61\xCC\x81" (UTF-8, D form) のどれでしょう? あるいはそれ以外の何かなのでしょうか? 実は、文字列のエンコードはスクリプトファイルのエンコード方式に従って行われるというのが正解です。 したがって、もしスクリプトが ISO-8859-1 で書かれているのなら、文字列も ISO-8859-1 でエンコードされます。その他のエンコードの場合も同様です。 しかし、Zend Multibyte が有効になっている場合は話が別です。 この場合は、スクリプトはどんなエンコーディングで書いてもかまいません (明示的に宣言することもできるし、自動検出させることもできます)。 スクリプトはその後で内部エンコーディングに変換されるので、 文字列リテラルも内部エンコーディングと同じ方式で符号化されます。 スクリプトのエンコーディング (あるいは、Zend Multibyte を有効にした場合の内部エンコーディング) には、一部制限があることに注意しましょう。 ひとことで言うと、ASCII の上位互換 でなければならないということです。 UTF-8 や ISO-8859-1 などがこれにあたります。 しかし、状態に依存する (たとえば、同じバイト値が、先頭にあるときとシフト状態にあるときで違う意味になる) エンコーディングは、問題になる可能性があります。

もちろん、利便性を考慮すれば、テキストを操作する関数が文字列のエンコードを扱う際に 何らかの前提に基づかざるを得ないこともあります。 残念ながら、PHP の各関数が文字列のエンコーディングを判断する方法はまったく統一されていません。

  • いくつかの関数は、文字列が何らかのシングルバイトエンコーディングで符号化されているものと見なします。 しかし、文字列内の各バイトが必ずしも特定の文字に変換できなくてもかまいません。 このタイプの関数は、substr()strpos()strlen()strcmp() などです。 これらの関数については、文字列を扱うというよりメモリ上のバッファを扱うものととらえてもよいでしょう。 つまり、バイト列とバイトオフセットで考えるということです。
  • 文字列のエンコーディングを受け取る関数もあります。 エンコーディング情報を省略したときにはデフォルトを用意していることもあるでしょう。 このタイプの関数の例は、htmlentities() や 大半の mbstring 関数です。
  • 現在のロケール (setlocale() を参照ください) を使うけれども、 処理はバイト単位で行う関数もあります。 このタイプの関数は strcasecmp()strtoupper() そして ucfirst() です。 つまり、これらの関数はシングルバイトエンコーディングでしか使えず、 さらにエンコーディングとロケールがマッチしていなければならないということです。 たとえば、strtoupper("á") が正しく "Á" を返すには、ロケールを正しく設定したうえで á をシングルバイトで符号化しておかなければなりません。仮に UTF-8 を使っていたとすると、 正しい結果は返されないでしょう。さらに、現在のロケール設定によっては 返される文字列が壊れてしまう可能性もあります。
  • 最後に、文字列が特定のエンコーディング (たいていは UTF-8) であることを前提としている関数があります。 intl の関数や PCRE の関数 (u 修飾子を使う場合のみ) の多くがこのタイプになります。また、その関数の目的上、 utf8_decode() 関数は入力が UTF-8 であることを前提とし、 utf8_encode() 関数は入力が ISO-8859-1 であることを前提としています。

結局、Unicode を使うプログラムをきちんと書くには、 うまく動かない関数の使わないよう注意するしかないということです。 特にデータを破壊してしまう可能性のある関数の使用は避け、 きちんと動作する関数を使うようにしましょう。 intlmbstring の関数を選択するとよいでしょう。 しかし、Unicode をまともに扱える関数を使うというのは単なる始まりに過ぎません。 たとえ関数側で Unicode を扱う機能があったとしても、 Unicode の仕様に関する知識は不可欠です。 たとえば、世の中には大文字と小文字しか存在しないという思い込みで作ったプログラムは、 うまく動かない可能性があります。

add a note add a note

User Contributed Notes 27 notes

up
358
John
7 years ago
I've been a PHP programmer for a decade, and I've always been using the "single-quoted literal" and "period-concatenation" method of string creation. But I wanted to answer the performance question once and for all, using sufficient numbers of iterations and a modern PHP version. For my test, I used:

php -v
PHP 7.0.12 (cli) (built: Oct 14 2016 09:56:59) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

------ Results: -------

* 100 million iterations:

$outstr = 'literal' . $n . $data . $int . $data . $float . $n;
63608ms (34.7% slower)

$outstr = "literal$n$data$int$data$float$n";
47218ms (fastest)

$outstr =<<<EOS
literal$n$data$int$data$float$n
EOS;
47992ms (1.64% slower)

$outstr = sprintf('literal%s%s%d%s%f%s', $n, $data, $int, $data, $float, $n);
76629ms (62.3% slower)

$outstr = sprintf('literal%s%5$s%2$d%3$s%4$f%s', $n, $int, $data, $float, $data, $n);
96260ms (103.9% slower)

* 10 million iterations (test adapted to see which of the two fastest methods were faster at adding a newline; either the PHP_EOL literal, or the \n string expansion):

$outstr = 'literal' . $n . $data . $int . $data . $float . $n;
6228ms (reference for single-quoted without newline)

$outstr = "literal$n$data$int$data$float$n";
4653ms (reference for double-quoted without newline)

$outstr = 'literal' . $n . $data . $int . $data . $float . $n . PHP_EOL;
6630ms (35.3% slower than double-quoted with \n newline)

$outstr = "literal$n$data$int$data$float$n\n";
4899ms (fastest at newlines)

* 100 million iterations (a test intended to see which one of the two ${var} and {$var} double-quote styles is faster):

$outstr = 'literal' . $n . $data . $int . $data . $float . $n;
67048ms (38.2% slower)

$outstr = "literal$n$data$int$data$float$n";
49058ms (1.15% slower)

$outstr = "literal{$n}{$data}{$int}{$data}{$float}{$n}"
49221ms (1.49% slower)

$outstr = "literal${n}${data}${int}${data}${float}${n}"
48500ms (fastest; the differences are small but this held true across multiple runs of the test, and this was always the fastest variable encapsulation style)

* 1 BILLION iterations (testing a completely literal string with nothing to parse in it):

$outstr = 'literal string testing';
23852ms (fastest)

$outstr = "literal string testing";
24222ms (1.55% slower)

It blows my mind. The double-quoted strings "which look so $slow since they have to parse everything for \n backslashes and $dollar signs to do variable expansion", turned out to be the FASTEST string concatenation method in PHP - PERIOD!

Single-quotes are only faster if your string is completely literal (with nothing to parse in it and nothing to concatenate), but the margin is very tiny and doesn't matter.

So the "highest code performance" style rules are:

1. Always use double-quoted strings for concatenation.

2. Put your variables in "This is a {$variable} notation", because it's the fastest method which still allows complex expansions like "This {$var['foo']} is {$obj->awesome()}!". You cannot do that with the "${var}" style.

3. Feel free to use single-quoted strings for TOTALLY literal strings such as array keys/values, variable values, etc, since they are a TINY bit faster when you want literal non-parsed strings. But I had to do 1 billion iterations to find a 1.55% measurable difference. So the only real reason I'd consider using single-quoted strings for my literals is for code cleanliness, to make it super clear that the string is literal.

4. If you think another method such as sprintf() or 'this'.$var.'style' is more readable, and you don't care about maximizing performance, then feel free to use whatever concatenation method you prefer!
up
92
gtisza at gmail dot com
12 years ago
The documentation does not mention, but a closing semicolon at the end of the heredoc is actually interpreted as a real semicolon, and as such, sometimes leads to syntax errors.

This works:

<?php
$foo
= <<<END
abcd
END;
?>

This does not:

<?php
foo
(<<<END
abcd
END;
);
// syntax error, unexpected ';'
?>

Without semicolon, it works fine:

<?php
foo
(<<<END
abcd
END
);
?>
up
11
Ray.Paseur sometimes uses Gmail
5 years ago
md5('240610708') == md5('QNKCDZO')

This comparison is true because both md5() hashes start '0e' so PHP type juggling understands these strings to be scientific notation.  By definition, zero raised to any power is zero.
up
19
garbage at iglou dot eu
7 years ago
You can use string like array of char (like C)

$a = "String array test";

var_dump($a);
// Return string(17) "String array test"

var_dump($a[0]);
// Return string(1) "S"

// -- With array cast --
var_dump((array) $a);
// Return array(1) { [0]=> string(17) "String array test"}

var_dump((array) $a[0]);
// Return string(17) "S"

- Norihiori
up
22
lelon at lelon dot net
19 years ago
You can use the complex syntax to put the value of both object properties AND object methods inside a string.  For example...
<?php
class Test {
    public
$one = 1;
    public function
two() {
        return
2;
    }
}
$test = new Test();
echo
"foo {$test->one} bar {$test->two()}";
?>
Will output "foo 1 bar 2".

However, you cannot do this for all values in your namespace.  Class constants and static properties/methods will not work because the complex syntax looks for the '$'.
<?php
class Test {
    const
ONE = 1;
}
echo
"foo {Test::ONE} bar";
?>
This will output "foo {Test::one} bar".  Constants and static properties require you to break up the string.
up
18
og at gams dot at
17 years ago
easy transparent solution for using constants in the heredoc format:
DEFINE('TEST','TEST STRING');

$const = get_defined_constants();

echo <<<END
{$const['TEST']}
END;

Result:
TEST STRING
up
3
vseokdog at gmail dot com
4 years ago
Don't forget about new E_WARNING and E_NOTICE errors from PHP 7.1.x: they have been introduced when invalid strings are coerced using operators expecting numbers (+ - * / ** % << >> | & ^) or their assignment equivalents. An E_NOTICE is emitted when the string begins with a numeric value but contains trailing non-numeric characters, and an E_WARNING is emitted when the string does not contain a numeric value.

Example:
$foo = 1 + "bob-1.3e3"; 
$foo = "10.2 pigs " + 1.0;
Will produce: Warning: A non-numeric value encountered

Read more: https://www.php.net/manual/en/migration71.other-changes.php
up
11
chAlx at findme dot if dot u dot need
15 years ago
To save Your mind don't read previous comments about dates  ;)

When both strings can be converted to the numerics (in ("$a" > "$b") test) then resulted numerics are used, else FULL strings are compared char-by-char:

<?php
var_dump
('1.22' > '01.23'); // bool(false)
var_dump('1.22.00' > '01.23.00'); // bool(true)
var_dump('1-22-00' > '01-23-00'); // bool(true)
var_dump((float)'1.22.00' > (float)'01.23.00'); // bool(false)
?>
up
4
sideshowAnthony at googlemail dot com
8 years ago
Something I experienced which no doubt will help someone . . .
In my editor, this will syntax highlight HTML and the $comment:

$html = <<<"EOD"
<b>$comment</b>
EOD;

Using this shows all the same colour:

$html = <<<EOD
<b>$comment</b>
EOD;

making it a lot easier to work with
up
3
mark at manngo dot net
7 years ago
I though that it would be helpful to add this comment so that the information at least appears on the right page on the PHP site.

Note that if you intend to use a double-quoted string with an associative key, you may run into the T_ENCAPSED_AND_WHITESPACE error. Some regard this as one of the less obvious error messages.

An expression such as:

<?php
    $fruit
=array(
       
'a'=>'apple',
       
'b'=>'banana',
       
//    etc
   
);

    print
"This is a $fruit['a']";    //    T_ENCAPSED_AND_WHITESPACE
?>

will definitely fall to pieces.

You can resolve it as follows:

<?php
   
print "This is a $fruit[a]";    //    unquote the key
   
print "This is a ${fruit['a']}";    //    Complex Syntax
   
print "This is a {$fruit['a']}";    //    Complex Syntax variation
?>

I have a personal preference for the last variation as it is more natural and closer to what the expression would be like outside the string.

It’s not clear (to me, at least) why PHP misinterprets the single quote inside the expression but I imagine that it has something to do with the fact quotes are not part of the value string — once the string is already being parsed the quotes just get in the way … ?
up
8
headden at karelia dot ru
14 years ago
Here is an easy hack to allow double-quoted strings and heredocs to contain arbitrary expressions in curly braces syntax, including constants and other function calls:

<?php

// Hack declaration
function _expr($v) { return $v; }
$_expr = '_expr';

// Our playground
define('qwe', 'asd');
define('zxc', 5);

$a=3;
$b=4;

function
c($a, $b) { return $a+$b; }

// Usage
echo "pre {$_expr(1+2)} post\n"; // outputs 'pre 3 post'
echo "pre {$_expr(qwe)} post\n"; // outputs 'pre asd post'
echo "pre {$_expr(c($a, $b)+zxc*2)} post\n"; // outputs 'pre 17 post'

// General syntax is {$_expr(...)}
?>
up
6
php at richardneill dot org
11 years ago
Leading zeroes in strings are (least-surprise) not treated as octal.
Consider:
  $x = "0123"  + 0;  
  $y = 0123 + 0;
  echo "x is $x, y is $y";    //prints  "x is 123, y is 83"
in other words:
* leading zeros in numeric literals in the source-code are interpreted as "octal", c.f. strtol().
* leading zeros in strings (eg user-submitted data), when cast (implicitly or explicitly) to integer are ignored, and considered as decimal, c.f. strtod().
up
5
steve at mrclay dot org
15 years ago
Simple function to create human-readably escaped double-quoted strings for use in source code or when debugging strings with newlines/tabs/etc.

<?php
function doubleQuote($str) {
   
$ret = '"';
    for (
$i = 0, $l = strlen($str); $i < $l; ++$i) {
       
$o = ord($str[$i]);
        if (
$o < 31 || $o > 126) {
            switch (
$o) {
                case
9: $ret .= '\t'; break;
                case
10: $ret .= '\n'; break;
                case
11: $ret .= '\v'; break;
                case
12: $ret .= '\f'; break;
                case
13: $ret .= '\r'; break;
                default:
$ret .= '\x' . str_pad(dechex($o), 2, '0', STR_PAD_LEFT);
            }
        } else {
            switch (
$o) {
                case
36: $ret .= '\$'; break;
                case
34: $ret .= '\"'; break;
                case
92: $ret .= '\\\\'; break;
                default:
$ret .= $str[$i];
            }
        }
    }
    return
$ret . '"';
}
?>
up
5
Richard Neill
16 years ago
Unlike bash, we can't do
  echo "\a"       #beep!

Of course, that would be rather meaningless for PHP/web, but it's useful for PHP-CLI. The solution is simple:  echo "\x07"
up
0
alain dot fouere at wanadoo dot fr
3 years ago
I've been a programmer in assembler(8086), GwBasic, C (++), Java (bytecode), etc. for a long time. I read in the present page :
"Strings
A string is series of characters, where a character is the same as a byte.
This means that PHP only supports a 256-character set, ...
.....
Details of the String Type
The string in PHP is implemented as an array of bytes and an integer indicating the length of the buffer.
.....
"
Therefore I'm quite sure that a PHP string (a Zend string) IS NOT an array() i.e. a map with keys and values, but an "array as in Pascal"(size indicated, no ending NULL char)  !
Hey guys, may you clearly and precisely explain this here ?
Sincerely. Alain.
up
-2
greenbluemoonlight at gmail dot com
3 years ago
<?php
\\Example # 10 Simple Syntax - Solution for the last "echo" line.

class people {
    public
$john = "John Smith";
    public
$jane = "Jane Smith";
    public
$robert = "Robert Paulsen";

    public
$smith = "Smith";
}

$people = new people();

echo
"$people->john then said hello to $people->jane.".PHP_EOL;
echo
"$people->john's wife greeted $people->robert.".PHP_EOL;
echo
"$people->robert greeted the two $people->smiths";
\\
Won't work
\\Outputs: Robert Paulsen greeted the two

/**Solution:**\

echo "$people->robert greeted the two $people->smith\x08s";

\\Will work
\\Outputs: Robert Paulsen greeted the two Smiths

?>
up
3
atnak at chejz dot com
20 years ago
Here is a possible gotcha related to oddness involved with accessing strings by character past the end of the string:

$string = 'a';

var_dump($string[2]);  // string(0) ""
var_dump($string[7]);  // string(0) ""
$string[7] === '';  // TRUE

It appears that anything past the end of the string gives an empty string..  However, when E_NOTICE is on, the above examples will throw the message:

Notice:  Uninitialized string offset:  N in FILE on line LINE

This message cannot be specifically masked with @$string[7], as is possible when $string itself is unset.

isset($string[7]);  // FALSE
$string[7] === NULL;  // FALSE

Even though it seems like a not-NULL value of type string, it is still considered unset.
up
-1
nospam at nospam dot com
7 years ago
Beware that consistent with "String conversion to numbers":

<?php

if ('123abc' == 123) echo '(intstr == int) incorrectly tests as true.';

// Because one side is a number, the string is incorrectly converted from intstr to int, which then matches the test number.

// True for all conditionals such as if and switch statements (probably also while loops)!

// This could be a huge security risk when testing/using/saving user input, while expecting and testing for only an integer.

// It seems the only fix is for 123 to be a string as '123' so no conversion happens.

?>
up
-2
shd at earthling dot net
14 years ago
If you want a parsed variable surrounded by curly braces, just double the curly braces:

<?php
  $foo
= "bar";
  echo
"{{$foo}}";
?>

will just show {bar}. The { is special only if followed by the $ sign and matches one }. In this case, that applies only to the inner braces. The outer ones are not escaped and pass through directly.
up
-3
necrodust44 at gmail dot com
10 years ago
String conversion to numbers.

Unfortunately, the documentation is not correct.

«The value is given by the initial portion of the string. If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero).»

It is not said and is not shown in examples throughout the documentation that, while converting strings to numbers, leading space characters are ignored, like with the strtod function.

<?php
   
echo "     \v\f    \r   1234" + 1;    // 1235
   
var_export ("\v\f    \r   1234" == "1234");    // true
?>

However, PHP's behaviour differs even from the strtod's. The documentation says that if the string contains a "e" or "E" character, it will be parsed as a float, and suggests to see the manual for strtod for more information. The manual says

«A hexadecimal number consists of a "0x" or "0X" followed by a nonempty sequence of hexadecimal digits possibly containing a radix character, optionally followed by a binary exponent.  A binary exponent consists of a 'P' or 'p', followed by an optional plus or minus sign, followed by a nonempty sequence of decimal digits, and indicates multiplication by a power of 2.»

But it seems that PHP does not recognise the exponent or the radix character.

<?php
   
echo "0xEp4" + 1;     // 15
?>

strtod also uses the current locale to choose the radix character, but PHP ignores the locale, and the radix character is always 2E. However, PHP uses the locale while converting numbers to strings.

With strtod, the current locale is also used to choose the space characters, I don't know about PHP.
up
-3
cvolny at gmail dot com
15 years ago
I commented on a php bug feature request for a string expansion function and figured I should post somewhere it might be useful:

using regex, pretty straightforward:
<?php
function stringExpand($subject, array $vars) {
   
// loop over $vars map
   
foreach ($vars as $name => $value) {
       
// use preg_replace to match ${`$name`} or $`$name`
       
$subject = preg_replace(sprintf('/\$\{?%s\}?/', $name), $value,
$subject);
    }
   
// return variable expanded string
   
return $subject;
}
?>

using eval() and not limiting access to only certain variables (entire current symbol table including [super]globals):

<?php
function stringExpandDangerous($subject, array $vars = array(), $random = true) {
   
       
// extract $vars into current symbol table
       
extract($vars);
       
       
$delim;
       
// if requested to be random (default), generate delim, otherwise use predefined (trivially faster)
       
if ($random)
           
$delim = '___' . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . '___';
        else
           
$delim = '__ASDFZXCV1324ZXCV__'// button mashing...
       
        // built the eval code
       
$statement = "return <<<$delim\n\n" . $subject . "\n$delim;\n";
       
       
// execute statement, saving output to $result variable
       
$result = eval($statement);
       
       
// if eval() returned FALSE, throw a custom exception
       
if ($result === false)
            throw new
EvalException($statement);
       
       
// return variable expanded string
       
return $result;
    }
?>

I hope that helps someone, but I do caution against using the eval() route even if it is tempting.  I don't know if there's ever a truely safe way to use eval() on the web, I'd rather not use it.
up
-3
bishop
18 years ago
You may use heredoc syntax to comment out large blocks of code, as follows:
<?php
<<<_EOC
    // end-of-line comment will be masked... so will regular PHP:
    echo (
$test == 'foo' ? 'bar' : 'baz');
    /* c-style comment will be masked, as will other heredocs (not using the same marker) */
    echo <<<EOHTML
This is text you'll never see!       
EOHTML;
    function defintion(
$params) {
        echo 'foo';
    }
    class definition extends nothing     {
       function definition(
$param) {
          echo 'do nothing';
       }      
    }

    how about syntax errors?; = gone, I bet.
_EOC;
?>

Useful for debugging when C-style just won't do.  Also useful if you wish to embed Perl-like Plain Old Documentation; extraction between POD markers is left as an exercise for the reader.

Note there is a performance penalty for this method, as PHP must still parse and variable substitute the string.
up
-3
webmaster at rephunter dot net
18 years ago
Use caution when you need white space at the end of a heredoc. Not only is the mandatory final newline before the terminating symbol stripped, but an immediately preceding newline or space character is also stripped.

For example, in the following, the final space character (indicated by \s -- that is, the "\s" is not literally in the text, but is only used to indicate the space character) is stripped:

$string = <<<EOT
this is a string with a terminating space\s
EOT;

In the following, there will only be a single newline at the end of the string, even though two are shown in the text:

$string = <<<EOT
this is a string that must be
followed by a single newline

EOT;
up
-5
jonijnm at example dot com
6 years ago
Both should work :(

<?php

class Testing {
    public static
$VAR = 'static';
    public const VAR =
'const';
   
    public function
sayHelloStatic() {
        echo
"hello: {$this::$VAR}";
    }
   
    public function
sayHelloConst() {
        echo
"hello: {$this::VAR}"; //Parse error:  syntax error, unexpected '}', expecting '['
   
}
}

$obj = new Testing();
$obj->sayHelloStatic();
$obj->sayHelloConst();
up
-8
rkfranklin+php at gmail dot com
16 years ago
If you want to use a variable in an array index within a double quoted string you have to realize that when you put the curly braces around the array, everything inside the curly braces gets evaluated as if it were outside a string.  Here are some examples:

<?php
$i
= 0;
$myArray[Person0] = Bob;
$myArray[Person1] = George;

// prints Bob (the ++ is used to emphasize that the expression inside the {} is really being evaluated.)
echo "{$myArray['Person'.$i++]}<br>";

// these print George
echo "{$myArray['Person'.$i]}<br>";
echo
"{$myArray["Person{$i}"]}<br>";

// These don't work
echo "{$myArray['Person$i']}<br>";
echo
"{$myArray['Person'$i]}<br>";

// These both throw fatal errors
// echo "$myArray[Person$i]<br>";
//echo "$myArray[Person{$i}]<br>";
?>
up
-8
Hayley Watson
6 years ago
Any single expression, however complex, that starts with $ (i.e., a variable) can be {}-embedded in a double-quoted string:

<?php

echo "The expression {$h->q()["x}"]->p(9 == 0 ? 17 : 42)} gets parsed just as well as " . $h->q()["x}"]->p(9 == 0 ? 17 : 42) . " does.";

?>
up
-19
M. H. S.
4 years ago
<?php

// Its A Example for "Heredoc":

$n = 10;

$var_heredoc = <<<HEREDOC

Its A String For "
$var_heredoc" variable.

heredoc can expanding variables.
(example:
$n)

if you want not expanding, you need print " \ " befor variable.
(example: /
$n)

heredoc can use " /n, /t, /r, ... ".

heredoc = the string of double-qoutation;

        HEREDOC; -> its bad closing of heredoc!

HEREDOC;
// its a good closing of heredoc!

?>
To Top